Dart 语言中文教程
翻译自 Dart 官网,查看原文。欢迎提供修改意见。
另见:Dart 库教程。
当前版本:2.2.0 (stable)
完成度:100%
这篇文章展示如何使用 Dart 的各个主要特性,从变量、运算符到类和库,并且假定你已经会使用其他编程语言编写
代码。 要详细了解 Dart 核心库相关内容,请查阅 Dart 库教程。当你想对一个语言特性深入了解时,无论何时都可
以查阅 Dart 语言规范。
小提示:在 DartPad 上,你可以尝试 Dart 的大部分语言特性(了解更多)。
转到 DartPatd。
目录
一个基本的 Dart 程序
重要概念
关键词
变量
默认值
Final 和 const
内置类型
数值
字符串
布尔
Lists
Sets
Maps
Runes
Symbols
函数
可选参数
main() 函数
函数作为一等对象
匿名函数
词法作用域
词法闭包
验证函数的相等性
返回值
运算符
算术运算符
相等和关系运算符
类型检查运算符
赋值运算符
逻辑运算符
按位和移位运算符
条件运算符
级联符号
其他运算符
控制流语句
If 和 else
For 循环
While 和 do-while 循环
Break 和 continue
Switch 和 case
断言
异常
类
Throw
Catch
Finally
使用类成员
使用构造函数
获取对象类型
实例变量
构造函数
方法
抽象类
隐式接口
继承类
重写类成员
枚举类型
为类添加特性:混入
类变量和方法
泛型
为什么用泛型?
使用集合字面量
在构造函数中使用参数类型
泛型集合和它们包含的类型
限制参数类型
使用泛型方法
库和可见性
使用库
实现库
异步支持
处理 Futures
声明异步函数
处理 Streams
生成器
可被调用的类
Isolates
Typedefs
元数据
注释
单行注释
多行注释
文档注释
总结
译者总结
一个基本的 Dart 程序
下面的代码使用了 Dart 的许多基本特性:
// 定义函数
printInteger(int aNumber) {
print('The number is $aNumber.'); // 打印到控制台
}
// 这里是程序开始执行的地方
main() {
var number = 42; // 定义并初始化变量
printInteger(number); // 调用函数
}
下面是这个程序使用的可适用于所有 (almost) Dart 应用的特性:
// 这是一个单行注释
一个单行注释。Dart 也支持多行和文档注释。详情请参阅 注释。
int
一个类型。其他的一些 内置类型 包括字符串、List 和布尔。
42
一个数值字面量。数值字面量是一种编译期常量。
print()
一个方便的展示输出方式。
'...' (or "...")
一个字符串字面量。
$variableName (or ${expression})
字符串插值:插入一个变量或者表达式的字符串值到一个字符串字面量里。详情请参阅 字符串。
main()
应用开始执行的特定的、必须的、顶级的函数。详情请参阅 main() 函数。
var
一种声明变量但是不指定类型的方法。
提示:本篇文章的代码遵从 Dart 风格指南 中的公约。
重要概念
当你学习 Dart 语言的时候,请记住以下事实和概念:
,而且所有对象都是
的实例。每一个数值、函数和 null 都是对
所有可以放在一个变量里面的东西都是
象。所有的对象都继承自 Object 类。
尽管 Dart 是强类型的,但是 Dart 支持类型推断所以类型声明是可选的。在上面的代码中,number 被推断为
类型 int。当你想要显式声明没有预期的类型时,使用特殊的 dynamic 类型。
Dart 支持泛型,像是 List(包含整数的列表)或者 List(一个包含任意类型对象的列表)。
除了绑定在类和对象上的函数(分别为静态方法和实例方法)以外,Dart 还支持顶级函数(像 main())。你还
可以在函数中创建函数(嵌套函数或局部函数)。
不像 Java,Dart 没有这些关键词:pubilc,protected,private。如果一个标识符以下划线 (_) 开头,那么对
于它的库来说是私有的。详情请参阅 库和可见性。
标识符可以以下划线 (_) 开头,后面跟上任意字母和数字的组合。
Dart 既有“表达式”(具有运行时的值)也有“语句”(没有运行时的值)。例如,条件表达式 condition ? expr1
: expr2 有 expr1 或 expr2 的值。相对的一个 if-else 语句,是没有值的。一个语句经常包含一个或多个表达
式,但是一个表达式不能直接包含一个语句。
Dart 开发工具会报告两种类型的问题:"警告"和"错误"。警告只是表明你的代码可能无法正常工作,但是并不
会禁止你执行程序。错误可能是编译期或者运行期的。一个编译期错误完全禁止程序的执行;而运行期错误会
在代码执行到这里时抛出一个 异常。
关键词
下面的表格列出了 Dart 语言特殊对待的关键词。
对
象
类
abstract 2
dynamic 2
implements 2
as 2
assert
async 1
await 3
break
case
catch
class
const
continue
covariant 2
default
deferred 2
do
else
enum
export 2
extends
external 2
factory 2
false
final
finally
for
Function 2
get 2
hide 1
if
import 2
in
interface 2
is
library 2
mixin 2
new
null
on 1
operator 2
part 2
rethrow
return
set 2
show 1
static 2
super
switch
sync 1
this
throw
true
try
typedef 2
var
void
while
with
yield 3
避免使用这些单词作为标识符。然而,如果必要,带角标的关键词可以作为标识符:
带角标 1 的是 上下文关键词,它们只在特定的地方有有意义。除此之外他们在所有地方都是合法的关键词。
带角标 2 的是 内置标识符。为了简化将JavaScript代码移植到Dart的任务,这些关键字在大多数地方都是有效
的标识符,但它们不能用作类或类型名称,也不能用作导入前缀。
带角标 3 的是新的,与 异步支持 相关的限制性关键词,在 Dart 1.0 发布后才被加入。在以 async、async* 或
yield 标识的函数体中,你不能使用 async、await 或者 yield 作为标识符。
关键词表里的其他所有单词都是保留词。你不能使用它们作为标识符。
变量
这里是创建并初始化一个变量的例子:
var name = 'Bob';
变量保存的是引用。名字是 name 的变量包含一个指向值为 "Bob" 的字符串对象的引用。
名字为 name 的变量类型被推断为 String,但是你可以通过显示指定类型来改变这个行为。如果对象不限于一个单
一类型,指定它为 Object 或 dynamic 类型。
dynamic name = 'Bob';
另一个选择是显式指定类型为它将会被推断的类型:
String name = 'Bob';
提示:对于局部变量,本篇文章遵守 代码风格推荐 使用 var,而不是类型声明。
默认值
未初始话的变量有一个初始值 null。即使是数值类型的变量初始值也是 null,因为数值——和 Dart 中其他所有类型
一样——都是对象。
int lineCount;
assert(lineCount == null);
说明:代码中的 assert() 调用。在开发时,assert(condition) 会抛出一个异常,除非 condition 的结果是
true。详情请参阅 断言。
Final 和 const
如果你从不打算改变一个变量,请使用 final 和 const,而不是 var 或者一个类型名。Final 变量只可以被设置一
次;而 const 变量是编译期常量。(Const 变量是隐式 final 的。)一个 final 的顶级变量或者类变量在首次被使用时
初始化。
提示:实例变量只可以是 final 的,不可以是 const 的。Final 实例变量必须在构造函数体开始前被初始化——
在变量声明时、通过构造函数参数或者在构造函数的 初始化列表 中。
这里是创建并设置一个 final 变量的例子:
final name = 'Bob'; // 没有类型声明
final String nickname = 'Boddy';
你不可以改变一个 final 变量的值:
name = 'Alice'; // 错误:一个 final 变量只可以被设置一次
对那些你想要作为编译期常量的变量使用 const。如果这个 const 变量是类级别的,使用 static const 标识它。在
你声明的时候,设置变量的值为编译期常量比如数字、字符串字面量、另一个常量或者常量数值的算术运算结果。
const bar = 1000000; // 压力单位(达因/cm2)
const double atm = 1.01325 * bar; // 标准大气压
Const 关键词不仅可以声明常量。你还可以使用它创建常量值,也可以声明创建常量值的构造函数。任何变量都可以
拥有一个常量值。
var foo = const [];
final bar = const [];
const baz = []; // 等同于 `const []`
你可以忽略常量声明中初始化表达式中的 const,像上面的 baz 一样。详情请参阅 不要重复使用 const。
你可以改变一个非 final 且非 const 变量的值,即使它有一个常量值。
foo = [1, 2, 3]; // 之前是 const []
你不可以改变一个常量的值:
baz = [42]; // 错误:常量不可以被赋值
要了解更多使用 const 创建常量值的内容,请参阅 List、Map 和类。
内置类型
Dart 语言对以下类型有特殊的支持:
numbers(数值)
strings(字符串)
booleans(布尔)
lists(列表,也称为数组)
maps(映射)
runes(在字符串中表示一个Unicode字符)
symbols
你可以使用字面量初始化以上任意类型。比如,'this is a string' 就是一个字符串字面量,而 true 是一个 boolean
字面量。
由于 Dart 中的所有变量都是对象的引用——一个类的实例——所有你通常可以使用“构造函数”来初始化变量。某些
内置类型有它们自己的构造函数。比如,你可以使用 Map() 构造函数创建一个 map。
数值
Dart 中的数值有两种类型:
int
小于等于64位的整数值,实际长度依赖运行平台。在 Dart 虚拟机上,可以是 -263 到 263 次方 -1。编译到 JavaScript
的 Dart 使用 JavaScript的数值,允许从 -253 到 253 - 1的值。
double
64位(双精度)浮点数值,如 IEE 754 标准中所规定的。
Int 和 double 都是 num 的子类。Num 类型包含像 +,-,/ 和 * 这样的基本运算符,也是 abs()、ceil() 和 floor()
适用的类型。(像 >> 这样的位运算符定义在 int 类中。)如果你从 num 和它的子类中找不到你想要的,试着看看
dart:math 库。
整数是没有小数点的数字。下面是一些定义整数字面量的例子:
int x = 1;
int hex = 0xDEADBEEF;
如果一个数字包含小数点,那么它是一个浮点数。下面是一些定义浮点数字面量的例子:
var y = 1.1;
var exponents = 1.42e5;
在 Dart 2.1 中,数字字面量在必要时会自动转换为 double:
double z = 1; // 等效于 double z = 1.0
版本说明:在 Dart 2.1 之前,在 double 上下文中使用一个整数字面量会引发一个错误。
下面是一些数值和字符串互相转换的例子:
// String -> int
var one = int.parse('1');
assert(one == 1);
// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString();
assert(oneSAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
整数类型支持传统的位运算符,比如移位 (<<, >>) 、按位与 (&) 和按位或 (|)。下面是一个例子:
assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111
以字面量定义的数值是编译期常量。许多算术表达式也同样是编译器常量,只要它们的操作数是编译期常数且最后得
到一个数值。
const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;
字符串