Dart
-
基础语法
-
定义变量
// 定义变量 var name = 'bryce'; //使用var 定义变量string类型后无法修改值的类型 name = 123 // error 无法改变值的类型 // 默认值 int lineCount; // 定义一个变量不赋值 默认赋值为Null lineCount == null // true // 可选的类型 String name = 'bryce' // 定义一个类型为String的变量类型, /*tips:添加类型可以更加清晰的表达你的意图。 IDE 编译器等工具有可以使用类型来更好的帮助你, 可以提供代码补全、提前发现 bug 等功能。*/ -
内置类型
Dart 内置支持下面这些类型:
1.numbers (数值)
-
int 整数
-
double 浮点数
-
num 基本操作符 是int和double的父类
例如+,-,/,* 还定义了
abs()、ceil()、和floor()等 函数。 (位操作符,例如 >> 定义在int类中。)
some Function
var one = int.parse('1'); assert(one == 1); // String -> double var onePointOne = double.parse('1.1'); assert(onePointOne == 1.1); // True // int -> String String oneAsString = 1.toString(); assert(oneAsString == '1'); //True // double -> String String piAsString = 3.14159.toStringAsFixed(2); assert(piAsString == '3.14'); //True2.strings
Dart 字符串是 UTF-16 编码的字符序列。 可以使用单引号或者双引号来创建字符串:
var s1 = 'Single quotes work well for string literals.'; var s2 = 'It\'s easy to escape the string delimiter.'; // 字符串中使用表达式 var k1 = 'world'; var s4 = 'hello ${k1}'; // 字符串连接 使用 + 号 连接字符串 var t1 = "The + operator" + "works, as well.“ // 三个单引号双引号也可以创建多行字符串 """hello world"""3.booleans
当 Dart 需要一个布尔值的时候,只有
true对象才被认为是 true。 所有其他的值都是 flase。这点和 JavaScript 不一样, 像1、"aString"、 以及someObject等值都被认为是 false。4.lists (也被称之为 arrays)
在 Dart 中数组就是 List 对象。所以 通常我们都称之为 lists。
//下面是一个 Dart list 的示例: var list = [1, 2, 3]; /* Lists 的下标索引从 0 开始 第一个元素的索引是 0. list.length - 1 是最后一个元素的索引。 访问 list 的长度和元素与 JavaScript 中的用法一样:*/ var list = [1, 2, 3]; llist.length // 3 list[1] = 1; //true list[1] == 1 // true //在 list 字面量之前添加 const 关键字,可以 定义一个不变的 list 对象(编译时常量): var constlist = const [1,2,3] // 定义一个常量值 constlist[1] = 5 // Uncommenting this causes an error.5.maps
通常来说,Map 是一个键值对相关的对象。 键和值可以是任何类型的对象。每个 键 只出现一次, 而一个值则可以出现多次。
// 创建Map的方法和js一样 var gifts = { // Keys Values 'first' : 'partridge', 'second': 'turtledoves', 'fifth' : 'golden rings' }; // 使用 Map 构造函数也可以实现同样的功能: var gifts = new Map(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings'; // 添加值 gifts['child'] = 'children'; gifts['child'] == 'children'; // ture // 获取map键值对的数目 gifts.length // 4 // 同样使用 const 可以创建一个 编译时常量的 map: final constMap = const { 2: 'helium', 10: 'neon', 18: 'argon' } coustMap[2] = 'hu'; // Uncommenting this causes an error.6.runes (用于在字符串中表示 Unicode 字符)
在 Dart 中,runes 代表字符串的 UTF-32 code points。
Unicode 为每一个字符、标点符号、表情符号等都定义了 一个唯一的数值。 由于 Dart 字符串是 UTF-16 code units 字符序列, 所以在字符串中表达 32-bit Unicode 值就需要 新的语法了。
通常使用
\uXXXX的方式来表示 Unicode code point, 这里的 XXXX 是4个 16 进制的数。 例如,心形符号 (♥) 是\u2665。 对于非 4 个数值的情况, 把编码值放到大括号中即可。 例如,笑脸 emoji (😆) 是\u{1f600}。String 类 有一些属性可以提取 rune 信息。
codeUnitAt和codeUnit属性返回 16-bit code units。 使用runes属性来获取字符串的 runes 信息。var clapping = '\u{1f44f}'; print(clapping); print(clapping.codeUnits); print(clapping.runes.toList()); Runes input = new Runes( '\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}'); print(new String.fromCharCodes(input));7.symbols
-
-
2.Functions(方法)
Dart 是一个真正的面向对象语言,方法也是对象并且具有一种 类型,
Function。 这意味着,方法可以赋值给变量,也可以当做其他方法的参数。 也可以把 Dart 类的实例当做方法来调用。
下面是定义方法的示例:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
/* 解析:bool定义的是方法需要返回一个布尔值
isNoble 方法名
int atomicNumber 传入为int形的参数
/*
// 虽然在 Effective Dart 中推荐 在公开的 APIs 上使用静态类型, 你当然也可以选择忽略类型定义:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
// Tips: 那这样其实也和咱们js一样了嘛 但是要记住一点 加入类型的断定可以帮助提前发现错误,减少语法bug
//对于只有一个表达式的方法,你可以选择 使用缩写语法来定义:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null; //语法类似es6箭头函数
Optional parameters(可选参数)
可选参数可以是命名参数或者基于位置的参数,但是这两种参数不能同时当做可选参数。
Optional named parameters(可选命名参数)
调用方法的时候,你可以使用这种形式 *paramName*: *value* 来指定命名参数。例如:
// 定义方法 参数名为:bold ,hidden
enableFlags({bool bold, bool hidden}) {
// ...
}
// 传入参数名为:bold,hidden
enableFlags(bold: true, hidden: false);
Optional positional parameters(可选位置参数)
把一些方法的参数放到 [] 中就变成可选 位置参数了:
// 定义一个String类型的位置参数 [String device]
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
// 不使用可选参数调用上面方法的示例:
say('Bob', 'Howdy') == 'Bob says Howdy';
// 使用可选参数调用上面方法的示例:
say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal';
Default parameter values(默认参数值)
在定义方法的时候,可以使用 = 来定义可选参数的默认值。 默认值只能是编译时常量。 如果没有提供默认值,则默认值为 null。
下面是设置可选参数默认值的示例:
void enableFlags({bool bold = false, bool hidden = false}) {
// ...
}
// 调用enableFlags 因此 enableFlags 内部 bold = true hidden默认false
enableFlags(bold:true)
下面的示例显示了如何设置位置参数的默认值:
String say(String from, String msg,[String device = 'carrier pigeon', String mood]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
if (mood != null) {
result = '$result (in a $mood mood)';
}
return result;
}
say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon' // True
还可以使用 list 或者 map 作为默认值。 下面的示例定义了一个方法 doStuff(), 并分别为 list 和 gifts 参数指定了 默认值。
void doStuff({List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
The main() function(入口函数)
每个应用都需要有个顶级的 main() 入口方法才能执行。 main() 方法的返回值为 void 并且有个可选的 List<String> 参数。
下面是一个 web 应用的 main() 方法:
void main() {
querySelector("#sample_text_id")
..text = "Click me!"
..onClick.listen(reverseText);
}
// 注意: 前面代码中的 .. 语法为 级联调用(cascade)。 使用级联调用语法, 你可以在一个对象上执行多个操作。
// 类似js的链式调用
new Promise().then().then().catch()
下面是一个命令行应用的 main() 方法,并且使用了 方法参数作为输入参数:
// Run the app like this: dart args.dart 1 test
void main(List<String> arguments) {
print(arguments);
assert(arguments.length == 2);
assert(int.parse(arguments[0]) == 1);
assert(arguments[1] == 'test');
}
Functions as first-class objects(一等方法对象)
可以把方法当做参数调用另外一个方法。例如:
printElement(element) {
print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
方法也可以赋值给一个变量:
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
Anonymous functions(匿名方法)
大部分方法都带有名字,例如 main() 或者 printElement()。 你有可以创建没有名字的方法,称之为 匿名方法
/*
下面的代码定义了一个参数为i (该参数没有指定类型)的匿名函数。 list 中的每个元素都会调用这个函数来 打印出来,同时来计算了每个元素在 list 中的索引位置。
/*
var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums'];
list.forEach((i) {
print(list.indexOf(i).toString() + ': ' + i);
});
//如果方法只包含一个语句,可以使用`箭头函数`
list.forEach((i) => print(list.indexOf(i).toString() + ': ' + i));
Lexical scope(静态作用域)
Dart 是静态作用域语言,变量的作用域在写代码的时候就确定过了。 基本上大括号里面定义的变量就 只能在大括号里面访问
var topLevel = true;
main() {
var insideMain = true;
myFunction() {
var insideFunction = true;
nestedFunction() {
var insideNestedFunction = true;
assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}
// 以上nestedFunction方法里可以访问任何上面定义的任何变量
Lexical closures(闭包)
一个 闭包 是一个方法对象,不管该对象在何处被调用, 该对象都可以访问其作用域内 的变量。
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
Testing functions for equality(测试函数是否相等)
foo() {} // A top-level function
class A {
static void bar() {} // A static method
void baz() {} // An instance method
}
main() {
var x;
// Comparing top-level functions.
x = foo;
assert(foo == x);
// Comparing static methods.
x = A.bar;
assert(A.bar == x);
// Comparing instance methods.
var v = new A(); // Instance #1 of A
var w = new A(); // Instance #2 of A
var y = w;
x = w.baz;
/*
这些闭包引用同一个实例,
所以它们是相等的。
*/
assert(y.baz == x);
/*
这些闭包引用不同的实例,
所以他们是不平等的。
*/
assert(v.baz != w.baz);
}
3.Operators(操作符)
下表是 Dart 中定义的操作符。 很多操作符都可以重载,详情参考 Overridable operators。
| 描述 | 操作符 |
|---|---|
| unary postfix | *expr*++ *expr*-- () [] . ?. |
| unary prefix | -*expr* !*expr* ~*expr* ++*expr* --*expr* |
| multiplicative | * / % ~/ |
| additive | + - |
| shift | << >> |
| bitwise AND | & |
| bitwise XOR | ^ |
| bitwise OR | | |
| relational and type test | >= > <= < as is is! |
| equality | == != |
| logical AND | && |
| logical OR | || |
| if null | ?? |
| conditional | *expr1* ? *expr2* : *expr3* |
| cascade | .. |
| assignment | = *= /= ~/= %= += -= <<= >>= &= ^= |= ??= |
Type test operators(类型判定操作符)
as、 is、 和 is! 操作符是在运行时判定对象 类型的操作符:
Type test operators(类型判定操作符)
as、 is、 和 is! 操作符是在运行时判定对象 类型的操作符:
| 操作符 | 解释 |
|---|---|
as |
类型转换 |
is |
如果对象是指定的类型返回 True |
is! |
如果对象是指定的类型返回 False |
Conditional expressions(条件表达式)
Dart 有一个特殊的操作符
*expr1* ?? *expr2*
如果 expr1 是 non-null,返回其值; 否则执行 expr2 并返回其结果。
类似 JavaScript: expr1 || expr2
Cascade notation (..)(级联操作符)
级联操作符 (..) 可以在同一个对象上 连续调用多个函数以及访问成员变量。 使用级联操作符可以避免创建 临时变量, 并且写出来的代码看起来 更加流畅:
querySelector('#button') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
类似 JavaScript: 链式调用
上面的代码和下面的代码功能一样:
var button = querySelector('#button');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
Other operators(其他操作符)
下面是其他操作符:
| Operator | Name | Meaning |
|---|---|---|
() |
使用方法 | 代表调用一个方法 |
[] |
访问 List | 访问 list 中特定位置的元素 |
. |
访问 Member | 访问元素,例如 foo.bar 代表访问 foo 的 bar 成员 |
?. |
条件成员访问 | 和 . 类似,但是左边的操作对象不能为 null,例如 foo?.bar 如果 foo 为 null 则返回 null,否则返回 bar 成员 |
4.Control flow statements(流程控制语句)
可以使用下面的语句来控制 Dart 代码的流程:
ifandelseforloopswhileanddo-whileloopsbreakandcontinueswitchandcaseassert
Dart for 循环中的闭包会捕获循环的 index 索引值, 来避免 JavaScript 中常见的问题。例如:
var callbacks = [];
for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());
Assert(断言)
如果条件表达式结果不满足需要,则可以使用 assert 语句俩打断代码的执行。 下面介绍如何使用断言。 下面是一些示例代码:
// Make sure the variable has a non-null value.
assert(text != null);
// Make sure the value is less than 100.
assert(number < 100);
// Make sure this is an https URL.
assert(urlString.startsWith('https'));
注意: 断言只在检查模式下运行有效,如果在生产模式 运行,则断言不会执行。
这里不过多介绍了 其他用法与javaScript都是一样的
5.Exceptions(异常)
代码中可以出现异常和捕获异常。异常表示一些 未知的错误情况。如果异常没有捕获, 则异常会抛出,导致 抛出异常的代码终止执行。
Throw
下面是抛出或者 扔出一个异常的示例:
throw new FormatException('Expected at least 1 section');
还可以抛出任意的对象:
throw 'Out of llamas!';
Catch
捕获异常可以避免异常继续传递(你重新抛出rethrow异常除外)。 捕获异常给你一个处理 该异常的机会:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e');
} catch (e) {
// No specified type, handles all
print('Something really unknown: $e');
}
如之前代码所示,你可以使用on 或者 catch 来声明捕获语句,也可以 同时使用。使用 on 来指定异常类型,使用 catch 来 捕获异常对象。
使用 rethrow 关键字可以 把捕获的异常给 重新抛出。
final foo = '';
void misbehave() {
try {
foo = "You can't change a final variable's value.";
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
Finally
要确保某些代码执行,不管有没有出现异常都需要执行,可以使用 一个 finally 语句来实现。如果没有 catch 语句来捕获异常, 则在执行完 finally 语句后, 异常被抛出了:
try {
breedMoreLlamas();
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}
6.Classes
Dart 是一个面向对象编程语言,同时支持基于 mixin 的继承机制。 每个对象都是一个类的实例,所有的类都继承于 Object.。 基于 Mixin 的继承 意味着每个类(Object 除外) 都只有一个超类,一个类的代码可以在其他 多个类继承中重复使用。
使用 new 关键字和构造函数来创建新的对象。 构造函数名字可以为 *ClassName* 或者*ClassName*.*identifier*。例如:
var jsonData = JSON.decode('{"x":1, "y":2}');
// Create a Point using Point().
var p1 = new Point(2, 2);
// Create a Point using Point.fromJson().
var p2 = new Point.fromJson(jsonData);
有些类提供了常量构造函数。使用常量构造函数 可以创建编译时常量,要使用常量构造函数只需要用 const 替代 new 即可:
var p = const ImmutablePoint(2, 2);
两个一样的编译时常量其实是 同一个对象:
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // They are the same instance!
每个实例变量都会自动生成一个 getter 方法(隐含的)。 Non-final 实例变量还会自动生成一个 setter 方法。详情, 参考 Getters and setters。
class Point {
num x;
num y;
}
main() {
var point = new Point();
point.x = 4; // Use the setter method for x.
assert(point.x == 4); // Use the getter method for x.
assert(point.y == null); // Values default to null.
}
Constructors
定义一个和类名字一样的方法就定义了一个构造函数 还可以带有其他可选的标识符,详情参考 Named constructors)(命名构造函数)。 常见的构造函数生成一个 对象的新实例:
class Point {
num x;
num y;
Point(num x, num y) {
// There's a better way to do this, stay tuned.
this.x = x;
this.y = y;
}
}
this 关键字指当前的实例。
注意: 只有当名字冲突的时候才使用 this。否则的话, Dart 代码风格样式推荐忽略 this。
Invoking a non-default superclass constructor(调用超类构造函数)
默认情况下,子类的构造函数会自动调用超类的 无名无参数的默认构造函数。 超类的构造函数在子类构造函数体开始执行的位置调用。 如果提供了一个 initializer list(初始化参数列表) ,则初始化参数列表在超类构造函数执行之前执行。 下面是构造函数执行顺序:
- initializer list(初始化参数列表)
- superclass’s no-arg constructor(超类的无名构造函数)
- main class’s no-arg constructor(主类的无名构造函数)
如果超类没有无名无参数构造函数, 则你需要手工的调用超类的其他构造函数。 在构造函数参数后使用冒号 (:) 可以调用 超类构造函数。
class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person {
// Person does not have a default constructor;
// you must call super.fromJson(data).
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}
main() {
var emp = new Employee.fromJson({});
// Prints:
// in Person
// in Employee
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'Bob';
}
由于超类构造函数的参数在构造函数执行之前执行,所以 参数可以是一个表达式或者 一个方法调用:
class Employee extends Person {
// ...
Employee() : super.fromJson(findDefaultData());
}
注意: 如果在构造函数的初始化列表中使用 super(),需要把它放到最后。 详情参考 Dart 最佳实践。
警告: 调用超类构造函数的参数无法访问 this。 例如,参数可以为静态函数但是不能是实例函数。
Initializer list(初始化列表)
在构造函数体执行之前除了可以调用超类构造函数之外,还可以 初始化实例参数。 使用逗号分隔初始化表达式。
class Point {
num x;
num y;
Point(this.x, this.y);
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map jsonMap)
: x = jsonMap['x'],
y = jsonMap['y'] {
print('In Point.fromJson(): ($x, $y)');
}
}
警告: 初始化表达式等号右边的部分不能访问 this。
Redirecting constructors(重定向构造函数)
有时候一个构造函数会调动类中的其他构造函数。 一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。
class Point {
num x;
num y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
Constant constructors(常量构造函数)
如果你的类提供一个状态不变的对象,你可以把这些对象 定义为编译时常量。要实现这个功能,需要定义一个 const 构造函数, 并且声明所有类的变量为 final。
class ImmutablePoint {
final num x;
final num y;
const ImmutablePoint(this.x, this.y);
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
}
Factory constructors(工厂方法构造函数)
如果一个构造函数并不总是返回一个新的对象,则使用 factory 来定义 这个构造函数。例如,一个工厂构造函数 可能从缓存中获取一个实例并返回,或者 返回一个子类型的实例。
下面代码演示工厂构造函数 如何从缓存中返回对象。
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to the _ in front
// of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = new Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) {
print(msg);
}
}
}
注意: 工厂构造函数无法访问 this。
使用 new 关键字来调用工厂构造函数。
var logger = new Logger('UI');
logger.log('Button clicked');
Getters and setters
Getters 和 setters 是用来设置和访问对象属性的特殊 函数。每个实例变量都隐含的具有一个 getter, 如果变量不是 final 的则还有一个 setter。 你可以通过实行 getter 和 setter 来创建新的属性, 使用 get 和 set 关键字定义 getter 和 setter:
class Rectangle {
num left;
num top;
num width;
num height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
main() {
var rect = new Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
getter 和 setter 的好处是,你可以开始使用实例变量,后来 你可以把实例变量用函数包裹起来,而调用你代码的地方不需要修改。
注意: 像 (++) 这种操作符不管是否定义 getter 都会正确的执行。 为了避免其他副作用, 操作符只调用 getter 一次,然后 把其值保存到一个临时变量中。
Implicit interfaces(隐式接口)
每个类都隐式的定义了一个包含所有实例成员的接口, 并且这个类实现了这个接口。如果你想 创建类 A 来支持 类 B 的 api,而不想继承 B 的实现, 则类 A 应该实现 B 的接口。
一个类可以通过 implements 关键字来实现一个或者多个接口, 并实现每个接口定义的 API。 例如:
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(who) => 'Hello, $who. I am $_name.';
}
// An implementation of the Person interface.
class Imposter implements Person {
// We have to define this, but we don't use it.
final _name = "";
String greet(who) => 'Hi $who. Do you know who I am?';
}
greetBob(Person person) => person.greet('bob');
main() {
print(greetBob(new Person('kathy')));
print(greetBob(new Imposter()));
}
7.Enumerated types(枚举类型)
枚举类型通常称之为 enumerations 或者 enums, 是一种特殊的类,用来表现一个固定 数目的常量。
Using enums
使用 enum 关键字来定义枚举类型:
enum Color {
red,
green,
blue
}
枚举类型中的每个值都有一个 index getter 函数, 该函数返回该值在枚举类型定义中的位置(从 0 开始)。 例如,第一个枚举值的位置为 0, 第二个为 1.
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
枚举的 values 常量可以返回 所有的枚举值。
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
Class variables and methods(类变量和函数)
使用 static 关键字来实现类级别的变量和函数。
Static variables(静态变量)
静态变量对于类级别的状态是 非常有用的:
class Color {
static const red =
const Color('red'); // A constant static variable.
final String name; // An instance variable.
const Color(this.name); // A constant constructor.
}
main() {
assert(Color.red.name == 'red');
}
静态变量在第一次使用的时候才被初始化。
注意: 这里准守代码风格推荐 命名规则,使用 lowerCamelCase 来命名常量。
Static methods(静态函数)
静态函数不再类实例上执行, 所以无法访问 this。例如:
import 'dart:math';
class Point {
num x;
num y;
Point(this.x, this.y);
static num distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
main() {
var a = new Point(2, 2);
var b = new Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(distance < 2.9 && distance > 2.8);
}
注意: 对于通用的或者经常使用的静态函数,考虑 使用顶级方法而不是静态函数。
8.Libraries and visibility(库和可见性)
使用 import 和 library 指令可以帮助你创建 模块化的可分享的代码。库不仅仅提供 API, 还是一个私有单元:以下划线 (_) 开头的标识符只有在库 内部可见。每个 Dart app 都是一个库, 即使没有使用 library命令也是一个库。
库可以使用 Dart package 工具部署。参考 Pub Package 和 Asset Manager 来获取关于 pub(Dart 的包管理工具) 的更多信息。
Using libraries(使用)
使用 import 来指定一个库如何使用另外 一个库。
例如, Dart web 应用通常使用 dart:html 库,然后可以这样导入库:
import 'dart:html';
import 必须参数为库 的 URI。 对于内置的库,URI 使用特殊的 dart: scheme。 对于其他的库,你可以使用文件系统路径或者 package: scheme。 package: scheme 指定的库通过包管理器来提供, 例如 pub 工具。
import 'dart:io';
import 'package:mylib/mylib.dart';
import 'package:utils/utils.dart';
注意: URI 代表 uniform resource identifier。 URLs (uniform resource locators) 是一种常见的 URI。
Specifying a library prefix(指定库前缀)
如果你导入的两个库具有冲突的标识符, 则你可以使用库的前缀来区分。 例如,如果 library1 和 library2 都有一个名字为 Element 的类, 你可以这样使用:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// ...
Element element1 = new Element(); // Uses Element from lib1.
lib2.Element element2 = new lib2.Element(); // Uses Element from lib2.
Importing only part of a library(导入库的一部分)
如果你只使用库的一部分功能,则可以选择需要导入的 内容。例如:
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
Lazily loading a library(延迟载入库)
Deferred loading (也称之为 lazy loading) 可以让应用在需要的时候再 加载库。 下面是一些使用延迟加载库的场景:
- 减少 APP 的启动时间。
- 执行 A/B 测试,例如 尝试各种算法的 不同实现。
- 加载很少使用的功能,例如可选的屏幕和对话框。
要延迟加载一个库,需要先使用 deferred as 来 导入:
import 'package:deferred/hello.dart' deferred as hello;
当需要使用的时候,使用库标识符调用 loadLibrary() 函数来加载库:
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
在前面的代码, 使用 await 关键字暂停代码执行一直到库加载完成。 关于 async 和 await 的更多信息请参考 异步支持。
Asynchrony support(异步支持)
Dart 有一些语言特性来支持 异步编程。 最常见的特性是 async 方法和 await 表达式。
Dart 库中有很多返回 Future 或者 Stream 对象的方法。 这些方法是 异步的: 这些函数在设置完基本的操作 后就返回了, 而无需等待操作执行完成。 例如读取一个文件,在打开文件后就返回了。
有两种方式可以使用 Future 对象中的 数据:
- 使用
async和await - 使用 Future API
看到这里我觉得大家都应该懂了 ,这里就不多做介绍了
await lookUpVersion()
要使用 await,其方法必须带有 async 关键字:
checkVersion() async {
var version = await lookUpVersion();
if (version == expectedVersion) {
// Do something.
} else {
// Do something else.
}
}
Metadata(元数据)
使用元数据给你的代码添加其他额外信息。 元数据注解是以 @ 字符开头,后面是一个编译时 常量(例如 deprecated)或者 调用一个常量构造函数。
有三个注解所有的 Dart 代码都可以使用: @deprecated、 @override、 和 @proxy。关于 @override 和@proxy 示例请参考 Extending a class。 下面是使用 @deprecated 的 示例:
class Television {
/// _Deprecated: Use [turnOn] instead._
@deprecated
void activate() {
turnOn();
}
/// Turns the TV's power on.
void turnOn() {
print('on!');
}
}
你还可以定义自己的元数据注解。 下面的示例定义了一个带有两个参数的 @todo 注解:
library todo;
class todo {
final String who;
final String what;
const todo(this.who, this.what);
}
使用 @todo 注解的示例:
import 'todo.dart';
@todo('seth', 'make this do something')
void doSomething() {
print('do something');
}
元数据可以在 library、 class、 typedef、 type parameter、 constructor、 factory、 function、 field、 parameter、或者 variable 声明之前使用,也可以在 import 或者 export 指令之前使用。 使用反射可以在运行时获取元数据 信息。