Flutter使用Dart来编写框架和widget, Dart可以使用DartPad来快速学习, 而无需搭建相关环境, 国内用户可以访问DartPad.cn。DartPad支持dart:* libraries
, 但是不支持dart:io
以及packages
。 如果你需要使用dart:io
那么你需要使用Dart SDK, 如果你需要使用packages
那么你需要使用平台, 对于开发移动应用, 你可以安装Flutter。
这里学习一下主要的Dart功能, 从变量、操作符、类到资源库。 如果你有其他语言基础, 那么学习Dart会很轻松。
Dart中重要的概念
- 所有的变量引用的都是对象, 所有的对象都是一个类得实例。甚至数字、函数和null都是对象, 所有的对象都继承于Object类。
- 虽然Dart是强类型, 但是在声明变量时可不指定类型, 因为Dart可以类型推导。如果想显式地声明一个不确定的类型, 可以使用
dynamic
或者基类Object
。- 示例
1 | void log(Object object) { |
- Dart支持泛型, 例如
List<int>
(一个整数集合)和List<dynamic>
(一个任意对象的集合)。 - Dart支持顶级函数(例如main()), 同时支持类或对象函数(静态方法和实例方法), 你也可以在函数中嵌套函数。
- Dart同样支持顶级变量以及在类或对象中创建静态和实例变量。实例变量有时被称为域或属性。
- 不像Java, Dart没有
public
,protectd
和private
限定符, 如果你定义一个以下划线(_)开始的变量, 那么它在库中就是私有的。 - 标示符由数字、字母、美元符号($)和下划线(_)构成, 但只能以字母或下划线开头。
- Dart有表达式和语句,表达式有值而语句没有. 例如条件表达式
condition ? expr1 : expr2
。一个语句通常包含一个或者多个表达式, 但是表达式不能只包含一个语句。 - Dart工具可以报告两类问题: 警告和错误。警告只表示你的代码可能不工作, 但是不会阻止你的程序执行。错误分为编译时错误和运行时错误, 编译时错误会阻止代码运行, 当代码执行时一个运行时错误会导致抛出一个异常。
Dart中关键字
应该避免使用下面的关键字作为标示符。
abstract | else | import | super |
as | enum | in | switch |
assert | export | interface | sync |
async | entends | is | this |
await | extension | library | throw |
break | external | mixin | true |
case | factory | new | try |
catch | false | null | typedef |
class | final | on | var |
const | finally | operator | void |
continue | for | part | while |
covariant | Function | rethrow | with |
default | get | return | yield |
deferred | hide | set | |
do | if | show | |
dynamic | implements | static |
变量
你可以隐式的声明变量, Dart会自动类型推导, 你也可以显示的声明变量的类型, 此时变量的类型就不能再变化(继承关系的除外)。如果变量的类型需要变化, 那么你可以使用Ojbect
或者dynamic
来定义。
var name1 = ‘Bob’; //推荐
dynamic name2 = ‘Bob’;
Object name3 = ‘Bob’;
String name4 = “Bob”;
变量的默认值
未初始化的变量默认值是null, 甚至未初始化的数值类型默认值也是null, 因为Dart中所有都是对象。
int lineCount;
assert(lineCount == null);
final 和 const
如果你不希望改变一个变量, 那么使用final
和const
取代var
修饰变量。一个final
变量只可以赋值一次, 而const
变量是一个编译时常量。
实例变量可以使用final
修饰但是不能使用const
修饰, final
修饰的变量必须在构造函数体前被初始化, 如在声明的时候或作为构造器参数, 或者initializer list
中。const
修饰的变量只能是具体数值, 不能是函数的返回值。如果const
修饰类中的变量, 则必须加上static
关键字, 即static const
。
1 | import 'dart:math'; |
内置类型
num
int
和double
都继承于num
, num
包含了一些基础的操作, 例如+
、-
、*
和/
, 同时你也会发现abs()
、floor()
、ceil()
和round()
等函数以及isNaN
、isEven
和isOdd
等属性。
1 | var x = 1; |
- int
- 整数值不超过64 bits, 这取决于平台。
- double
- double 是64 bits。
- 在Dart2.1及以后, 你也可以赋值int给double, 但是在Dart 2.1之前会报错。
- int、double和String的转换
1 | // String -> int |
整型支持传统的位移操作, 比如左移(向左边移位右侧补0)<<
、右移(向右移位左侧补0)>>
、按位与(都为1结果为1, 否则为0)&
、按位或(都为0结果为0, 否则为1)|
和按位异或(相同为1, 不相同为0)^
1 | assert((3 << 1) == 6); // 0011 << 1 == 0110 |
String
Dart中string是一个UTF-16编码的字符串, 你可以使用单引号'
或者双引号"
创建字符串。
1 | var s1 = 'Single quotes work well for string literals.'; |
你可以在字符串中使用${expression}
将表达式的值放在字符串中。如果expression
是一个变量标识, 那么你可以省略{}
, 你可以使用对象的toString()
方法获取相应的字符串对象。
1 | var s = 'string interpolation'; |
你也可以使用相邻字符串即使他们不在一行或者+
来连接字符串。
1 | var s1 = 'String ' |
另外一种创建多行字符串的方法是: 使用三个单引号'
或者三个双引号’”‘创建字符串。
1 | var s1 = ''' |
你可以在字符串前面加上r
创建一个原始字符串。
1 | var s = r'In a raw string, not even \n gets special treatment.'; |
bool
Dart中布尔有true
和false
, 它们都是编译时常量。
Dart是类型安全的, 这意味着你不能使用if (nonbooleanValue)
或者assert (nonbooleanValue)
进行判断, 如果需要判断请使用下面的方式:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);
// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);
// Check for null.
var unicorn;
assert(unicorn == null);
// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
List
大多数语言中叫Collection
或者Array
, 在Dart中类名是List
。
- 常用属性
- length: 长度
- reversed: 反转
- isEmpty: 是否为空
- isNotEmpty: 是否为非空
- 常用方法
- add(xxx): 添加元素
- addAll(xxx): 从List里面添加所有元素
- indexOf(xxx): 查找元素
- remove(xxx): 删除元素
- removeAt(xxx): 根据下标删除元素
- fillRange(xxx): 修改
- insert(index,value): 指定位置插入
- insertAll(index,list): 指定位置插入List
- toList(xxx): 转为List
- join(xxx): 转换成字符串
- forEach: 循环
- map
- where
- any
- every
- 相关其他类方法
- split(xxxx): 字符串转成List
1 | var list = [1, 2, 3]; |
Dart 2.3支持 ...
、...?
操作符, 同时可以使用collection if
和collection for
构建集合。
1 | var list1 = [1, 2, 3]; |
Set
Set
是一个无序不重复的集合。和List一样在Dart 2.3版本开始支持...
、...?
、condiction if
和condiction for
。
1 | var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'}; |
Map
通常来说, Map包含key、value对, key是唯一的。往Map中设置key-value时, 存在key则是修改, 不存在key则是添加。当从Map中根据key取value时, 不存在的key会返回null。和List一样在Dart 2.3版本开始支持...
、...?
、condiction if
和condiction for
。
- 常用属性
- keys: 获取所有key的值
- values: 获取所有value的值
- isEmpty: 是否为空
- isNotEmpty: 是否不为空
- 常用方法
- remove(xxx): 删除指定key的数据
- addAll(xxx): 合并
- containsValue(xxx): 是否包含值
- forEach: 循环
- map
- where
- any
- every
1 | var gifts = { |
如果Map中不存在key, 那么取值时会返回null
。
runes
Dart中表示UTF-32编码的字符串。
通常的表达方式是\uxxxx
, xxxx
表示4位16进制数。特殊情下如果多于或少于4位16进制数使用{}
括起来。
1 | var heart = '\u2665'; //♥ |
如果你需要读写单个 Unicode 字符,可以使用 characters 包中定义的 characters getter。它将返回 Characters 作为一系列 grapheme clusters 的字符串。下面是使用 characters API 的样例:
1 | import 'package:characters/characters.dart'; |
symbols
一个Symbols对象是Dart项目中的一个操作符或者标示符。你可能无需使用symbols, 但是对于通过名称指向标识的APIs却是有价值的。
使用#identifier
来使用一个标识的symbols。symbols是编译时常量。1
2#radix
#bar
Functions
在Dart中Function
也是对象, 这意味着你可以赋值Function
给变量或者作为参数传递给其他Function。1
2
3
4
5
6
7bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
//可以省略返回值类型或形参类型, 该函数同样可以正常运行, 建议最好还是指定类型
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
如果函数只包含一个表达式, 那么可以使用=>
简写的语法。1
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
一个Dart函数可以包括两种类型的参数: 必要参数(required)和可选参数(optional)。必要参数放在前面, 可选参数放在后面。可选命名参数可以使用@required
修饰表示它是必须的。
可选参数
可选参数可以是可选命名参数: Optional named parameters
或者可选位置参数: Optional positional parameters
, 在同一个函数中, 不能同时使用。
命名参数
Dart中定义Funtion时使用{param1, param2, ...}
来定义可选命名参数, 同时可以使用@required
表示它是必须的。
1 | void printValue({Object value1, Object value2}) { |
可选位置参数
Dart中定义Funtion时使用[]
包裹住参数来定义可选位置参数。
1 | void main() { |
参数默认值
Dart中定义函数使用=
来给可选名称变量或者可选位置变量一个默认值, 该默认值必须是编译时常量, 如果没有默认值, 那么默认值是null。
1 | void main() { |
main()主函数
每个App必须要有一个主函数main()
, 返回值为void
, 它有一个可选的List<String>
类型的参数arguments
。
1 | void main() { |
函数作为参数传递
你可以把函数作为参数传递给另外一个函数。
1 | void printElement(int element) { |
函数定义为变量
Dart执行将函数定义为一个变量。
1 | void main() { |
匿名函数
匿名函数就是没有方法名的函数。
定义语法:
([[Type] param1[, …]]) {
codeBlock;
};
1 | var list = ['apples', 'bananas', 'oranges']; |
作用域
Dart中定义的非静态变量的作用域一般是它所在的{}
内。
1 | bool topLevel = true; |
闭包
闭包是一个函数对象,它可以访问范围内的变量,甚至可以使用函数范围外的变量。
1 | Function makeAdder(num addBy) { |
Dart中全局函数、静态方法以及实例方法
函数的相等问题。
1 | void foo() {} // A top-level function |
函数的返回值
所有的函数都有返回值, 没有显示返回语句的函数最后一行默认执行return null;。
1 | foo() {} |
Operators
算术运算符
操作符 | 描述 |
---|---|
+ |
加 |
- |
减 |
-expr |
表示负数 |
* |
乘 |
/ |
除 |
~/ |
除, 返回整数 |
% |
求余 |
++var |
自增, 表达式取var+1 的值 |
var++ |
自增, 表达式取var 的值 |
--var |
自减, 表达式取var-1 的值 |
var-- |
自减, 表达式取var 的值 |
关系运算符
操作符 | 描述 |
---|---|
== |
等于, 特殊情况下两个对象完全相同可以使用identical() 方法, 如果== 两边都为null 返回true , 如果两个有一个为null , 另一个不为null 返回false 。同样的你也可以重新== 方法。 |
!= |
不等于 |
> |
大于 |
>= |
大于等于 |
< |
小于 |
<= |
小于等于 |
类型操作符
操作符 | 描述 |
---|---|
as |
1、强制类型转换(可能会抛出异常) 2、库别名 |
is |
判断对象是某种类型 |
is! |
判断对象不是某种类型 |
1 | if (emp is Person) { |
赋值操作符
描述 | 操作符 |
---|---|
= |
赋值 |
??= |
a ??= b , 如果a为null, 赋值b给a, 否则不赋值 |
–= |
a -= b 等价于 a = a - b |
/= |
a /= b 等价于 a = a / b |
%= |
a %= b 等价于 a = a % b |
>>= |
a >>= b 等价于 a = a >> b |
^= |
a ^= b 等价于 a = a ^ b |
&= |
a &= b 等价于 a = a & b |
|= | a |= b等价于 a = a | b |
+= |
a += b 等价于 a = a + b |
*= |
a *= b 等价于 a = a * b |
~/= |
a ~/= b 等价于 a = a ~/ b |
逻辑操作符
描述 | 操作符 |
---|---|
!expr |
逻辑非 |
|| | 逻辑或 |
&& |
逻辑与 |
位移操作符
描述 | 操作符 |
---|---|
& |
按位与 |
^ |
按位异或 |
| | 按位或 |
~expr |
补位 |
<< |
左位移 |
>> |
右位移 |
条件操作符
描述 | 操作符 |
---|---|
condition ? expr1 : expr2 |
条件为true取值expr1 , 否则取值expr2 |
expr1 ?? expr2 |
如果expr1 不为null返回expr1 , 否则返回expr2 |
1 | String playerName(String name) => name ?? 'Guest'; |
级联运算符 (..)
Cascade(..)
允许你多次操作同一个对象, 你可以调用函数, 也可以访问属性。值得注意的是, 如果一个方法返回值为void
的方法则不能使用级联运算符。1
2
3
4querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
其他操作符
描述 | 操作符 |
---|---|
() |
函数应用, 调用一个函数 |
[index] |
从List中根据下标取值 |
[key] |
从Map中根据key取值 |
. |
从对象中取属性值 |
?. |
从对象中取属性值, 如果对象为null那么取的值也为null |
流程控制语句
if-else
1 | if (isRaining()) { |
for
1 | var message = StringBuffer('Dart is fun'); |
捕获变量
Dart中for循环中的闭包(匿名函数)可以捕捉下标。
1 | void main() { |
for-in
Dart同样支持for-in
:
1 | var collection = [0, 1, 2]; |
while和 do-while
注意不要忘了do-while后的分号;
。
1 | while (!isDone()) { |
break和continue
1 | while (true) { |
Switch 和 case
Switch
语句在 Dart 中使用 ==
来比较整数、字符串或编译时常量,比较的两个对象必须是同一个类型且不能是子类并且没有重写 ==
操作符。
1 | var command = 'OPEN'; |
断言Assert
在开发中你可以使用assert(condition, optionalMessage);
, 当condition为false时, 会打断语句的执行。Debug
模式会执行, release生产环境不会执行。
1 | assert(urlString.startsWith('https')); |
异常Exceptions
Dart可以thorw
和catch
异常, 异常如果没有catch
, 那么有可能会导致应用程序终止。
Dart中所有的异常都是unchecked exceptions
, 方法不一定会声明其所抛出的异常并且你也不会被要求捕获任何异常。
throw
Dart中你可以把任何非null对象作为异常抛出, 注意: 生产环境一般抛出Error
或Exception
类型的异常。
1 | throw FormatException('Expected at least 1 section'); |
Catch
捕捉或捕获异常, 阻止异常传播(当然你也可以重新抛出异常)。
当你需要知道异常类型时你可以使用on
, 当你需要使用异常对象时, 你可以使用catch
。
1 | try { |
Catch的参数
catch可以有一个或者两个参数, 第一个参数是异常对象, 第二个参数是堆栈信息。
1 | try { |
rethrow
你也可以使用rethrow
重新抛出该异常。
1 | void misbehave() { |
Finally
不管有没有异常最后都会执行finally
中语句。
1 | try { |
类
Dart中所有对象都一个类的实例, 他们都继承于Object
类。Object
类是所有类(除了Object类本身)的超类。
使用对象中属性、方法
使用.
或者?.
来访问对象中的实例属性或者方法。
1 | var p = Point(2, 2); |
使用构造函数
从Dart 2开始, new
是可选的。
1 | var p1 = Point(2, 2); |
一些类提供常量构造函数, 在构造函数签使用const
关键字来创建编译时常量。
1 | var a = const ImmutablePoint(1, 1); |
对象的类型
获取一个对象的运行时类型使用对象的runtimeType
属性。
1 | print('The type of a is ${a.runtimeType}'); |
实例变量
所有未初始化的实例变量都是null。
1 | class Point { |
所有实例变量隐式生成getter方法, 一个非final
的实例变量默认还会隐式生成setter方法。
构造函数
创建一个类名相同的函数(额外的标识符是可选的), 声明一个构造函数。this
关键字表示当前对象。
1 | class Point { |
我们可以使用语法糖来进行快速创建构造函数。
1 | class Point { |
默认构造函数
如果你没有声明构造函数,那么 Dart 会自动生成一个无参数的构造函数并且该构造函数会调用其父类的无参数构造方法。如果存在有参数的构造函数, 那么就不会有默认的无参构造函数。
构造函数不能继承
构造函数是不能继承的, 这意味着假如在父类中定义了一个命名构造函数, 如果你想在子类中同样有相同名称的命名构造函数, 那么你实现该命名构造函数。
命名构造函数
1 | class Point { |
子类定义构造函数时默认先调用父类的构造函数, 当父类没有无参的构造函数时, 你必须手动调用父类有参构造函数之一。
你需要使用冒号(:)
在构造函数体前面。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class 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');
}
}
初始化器列表
除了调用父类构造函数, 你还有使用初始化器列表初始化变量在构造函数体执行之前。1
2
3
4
5
6
7
8
9
10class Point {
num x, y;
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
}
1 | import 'dart:math'; |
重定向构造函数
当一个类中有多个构造函数, 其他构造函数可以调用当前类的其他构造函数。1
2
3
4
5
6
7
8
9class Point {
num x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
常量构造函数
如果你生成的对象永远不会变化, 你可以使这些对象编译时常量。你只需定义一个const
构造函数, 然后设置所有实例变量final
。1
2
3
4
5
6
7
8class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
工厂构造函数
使用factory
关键字定义工厂构造函数时, 并不需要一直创建新的实例对象。
1 | class Logger { |
方法
方法是函数提供一个对象的行为。
实例方法
实例方法可以访问实例变量和实例方法。
1 | import 'dart:math'; |
Setter和Getter方法
Setter和Getter方法, 每个实例变量都会有一个隐式Getter方法, 根据实际情况生成隐式Setter方法, 当然也可以使用关键字set
和get
自己实现Getter和Setter方法。
1 | class Rectangle { |
抽象方法
实例变量、Getter、Setter都可以是抽象的, 抽象方法只能存在于抽象类中。抽象方法一般交给子类实现。
1 | abstract class Doer { |
抽象类
使用关键字abstract
定义抽象类, 它一般用于定义接口。
1 | abstract class AbstractContainer { |
隐式接口
每一个类都隐式地定义了一个接口并实现了该接口,这个接口包含所有这个类的实例成员以及这个类所实现的其它接口。如果想要创建一个 A 类支持调用 B 类的 API 且不想继承 B 类,则可以实现 B 类的接口。
一个类可以通过关键字 implements
来实现一个或多个接口并实现每个接口定义的 API:
1 | // A person. The implicit interface contains greet(). |
实现多个接口时:
1 | class Point implements Comparable, Location {...} |
继承类
使用关键字extends
来创建子类, super
指向它的父类。
1 | class Television { |
重写方法
使用@override
注解重写方法
1 | class SmartTelevision extends Television { |
重写操作符
重写operators
, 下面的操作符都是可以重写的
< | + | | | [] |
> | / | ^ | []= |
<= | ~/ | & | ~ |
>= | * | << | == |
– | % | >> |
!=
是不能重写的, 它只是相当于!(expr1 ==expr2)
。
1 | class Vector { |
如果你重写了==
操作符, 你同时需要重写hashCode
方法:
1 | class Person { |
noSuchMethod()
当你调用了一个对象的不存在的实例变量或者方法时, 重写noSuchMethod
即可检测到。
1 | class A { |
一般情况下, 你无法调用未实现的类, 除非下面几种情况:
1、调用者静态类型是dynamic
2、调用者类型是静态的, 但是定义了未实现的方法(如抽象类), 同时实现了noSuchMethod()
方法, 并且和Object
中的不一样。
Extension
使用extension
关键字可以定义方法、getter、setter和operator等。
1 | extension NumberParsing on String { |
枚举类型
使用enum
关键字定义枚举, 枚举中的值有一个index
的getter属性, 该属性返回该枚举值的从0
开始的位置。
1 | enum Color { red, green, blue } |
获取所有枚举值
1 | List<Color> colors = Color.values; |
在switch
中可以使用枚举值:
1 | var aColor = Color.blue; |
混入(mixin)
它是一种可以在多个类中重复使用另外同一个类代码的方式。使用关键字with
跟随一个或多个mixin
名称, 使用mixin
定义mixins, 并且可以使用关键字on
来指定哪些类可以使用该Mixin类。
1 | mixin Musical on Musician { |
静态变量和静态方法
使用static
来定义静态变量和静态方法, 静态变量只有在使用的时候才会初始化一次, 它是编译时常量。1
2
3
4
5
6
7
8
9
10
11class Queue {
static const initialCapacity = 16;
static void printCapacity() {
// ···
}
}
void main() {
assert(Queue.initialCapacity == 16);
}
泛型
如果你看的API文档基本类型List,你会发现实际上是Lit
当你使用了泛型List, 你就不能添加其他类型的对象到List中。1
2
3var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error
使用泛型可以减少重复代码1
2
3
4abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
集合字面量
List、Set使用<type>
, Map使用<Type, Type>
字面量定义泛型集合。1
2
3
4
5
6
7var names = <String>['Seth', 'Kathy', 'Lars'];
var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};
使用构造函数创建泛型集合
1 | var list = List<String>(); |
泛型集合的类型
Dart中泛型的类型是具体化的, 这意味着运行时你可以判断该类型, 在Java中你无法判断。1
2
3var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
限制参数类型
当我们使用泛型时, 希望限定某些类型可以使用extends
关键字。1
2
3
4
5
6
7
8
9
10
11
12
13
14class Foo<T extends SomeBaseClass> {
// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}
class Extender extends SomeBaseClass {...}
void main() {
var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
var foo = Foo();
var fooObject = Foo<Object>(); // 错误的写法
}
泛型方法
Dart同样支持泛型方法或者泛型函数。1
2
3
4
5
6T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
T tmp = ts[0];
// Do some additional checking or processing...
return tmp;
}
资源库和可见性
资源库Library
和import
可以方便的构建一个模块化和可共享的代码库。它不仅仅提供API, 以下划线(_)开始的标示符都只在该资源库中可见。每个Dart应用都是一个资源库。
内置库导入
1 | import 'dart:html'; |
其他库导入
1 | import 'package:test/test.dart'; |
指定库前缀
如果你导入了两个包含了相同标识的库, 那么你可以使用库前缀来区别他们。1
2
3
4
5
6
7
8import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
导入库的一部分
1 | // Import only foo. |
延迟加载库
延迟加载库运行应用程序在需要的时候加载库, 以下情况你可以使用延迟加载:
1、减少应用程序初始启动时间
2、例如执行A/B测试, 测试各种算法的不同实现
3、加载很少使用的功能, 例如可选的屏幕和对话框
目前只有dart2js支持延迟加载, Flutter暂不支持.
1 | //首先使用`deferred as`导入库 |
异步函数
关键字async
和await
可以用于异步编程, 使用await
的方法或者函数必须是async
。尽管异步函数可以处理耗时操作,但是它并不会等待这些耗时操作完成,异步函数执行时会在其遇到第一个 await
表达式的时候返回一个 Future
对象,然后等待 await
表达式执行完毕后继续执行。1
2
3
4Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
异常
使用try-catch-finally
处理异常和清理相关资源。1
2
3
4
5
6
7
8Future checkVersion() async {
try {
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
} catch (e) {
// React to inability to look up the version
}
}
await返回值
await expr
返回值都是Future类型的, 如果不是该类型, 系统会自动包装成Future类型。
声明异步函数
在函数声明中使用async
即可声明该函数为异步函数, 该函数返回值不用返回Future对象, Dart会自动包装。如果没有没有返回值, 确保返回Furhure<Void>
类型。1
2
3
4
5
6
7
8//同步函数
String lookUpVersion() => '1.0.0';
//异步函数
Future<String> lookUpVersion() async => '1.0.0';
Future<String> lookUpVersion() async {
return '1.0.0';
}
可调用类
实现call()
函数, 允许对象的实例像函数一样调用, 参数随意。1
2
3
4
5
6
7
8
9class WannabeFunction {
call(String a, String b) => '$a $b!';
}
main() {
var wf = new WannabeFunction();
var out = wf("Hi","there");
print('$out');
}
类型定义
使用typedef
给Function
命名, 这样可以保留相关的类型信息。
1 | typedef Compare = int Function(Object a, Object b); |
使用typedef
时可以使用泛型:
1 | typedef Compare<T> = int Function(T a, T b); |
元数据
元数据注解以 @
开头,其后紧跟一个编译时常量(比如 deprecated)或者调用一个常量构造函数。Dart 中有两个注解是所有代码都可以使用的:@deprecated
和 @override
。你也可以自定义注解:
1 | library todo; |