内置类型
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;
字符串
Dart 的字符串是以 UTF-16 编码单元组成的序列。你可以使用单引号或者双引号来创建字符串:
var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";
你可以使用 ${expression} 将一个表达式插入到字符串中。如果这个表达式是一个标识符,你可以省略 {}。为了得到一个对象的字符串表示,Dart 会调用对象的 toString() 方法。
var s = 'string interpolation';
assert('Dart has $s, which is very handy.' ==
'Dart has string interpolation, ' +
'which is very handy.');
assert('That deserves all caps. ' +
'${s.toUpperCase()} is very handy!' ==
'That deserves all caps. ' +
'STRING INTERPOLATION is very handy!');
说明:== 运算符测试两个对象是否相等。两个字符串相等的条件是它们包含同样的编码单位序列。
你可以通过并排字符串字面量或者使用 + 运算符来串联字符串:
var s1 = 'String '
'concatenation'
" works even over line breaks.";
assert(s1 ==
'String concatenation works even over '
'line breaks.');
var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');
另一种方式是创建一个多行字符串:使用三个引号(单引号或双引号)来标记:
var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";
你可以通过 r 前缀来创建一个”原始的“字符串:
var s = r"In a raw string, even \n isn't special.";
要详细了解 Unicode 字符在字符串中是怎样表示的,请参阅 Runes。
只要所有的插值表达式是编译期常量,计算结果为 null 或者 数值、字符串、布尔值,那么这个字符串字面量就是编译期常量。
// 可作为常量字符串的组成部分
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// 不可作为常量字符串的组成部分
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';
要了解更多使用字符串的信息,请参阅 字符串和正则表达式。
布尔
为了表示布尔值,Dart 内置了一个名字为 bool 的类型。只有两个对象拥有布尔类型:布尔字面量 true 和 false,它们两个都是编译期常量。
Dart 的类型安全意味着你不能使用像 if (nonbooleanValue) 这样的代码。取而代之,你需要明确地检查值,像是:
// 检查是否是空字符串
var fullName = '';
assert(fullName.isEmpty);
// 检查是否为0
var hitPoints = 0;
assert(hitPoints <= 0);
// 检查是否为空
var unicorn;
assert(unicorn == null);
// 检查是否是NaN
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
Lists
“数组”或者有序的对象组,也许是大部分编程语言中最常用的集合类型了。在 Dart 中,数组是类型为 List 的对象,所以人们通常称之为“列表”。
Dart 的列表字面量看起来就像 JavaScript 的数组字面量。下面是一个简单的 Dart 列表:
var list = [1, 2, 3];
说明:Dart 推断上面的 list 类型是 List<int>。如果你试图添加一个非整数值对象到这个列表中,分析器或者运行时会报告一个错误。要了解详细信息,请参阅 类型推断。
列表使用基于0的索引,也就是说 0 是列表中第一个元素的索引,而 list.length - 1 是最后一个元素的索引。你可以像 JavaScript 一样获取 list 的长度和它的元素:
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
要创建一个作为编译期常量的列表,在列表字面量前加上 const:
var constantList = const [1, 2, 3];
// constantList[1] = 1; // 这一行会引发一个错误
Dart 2.3 引入了 扩展运算符 (...) 和 空感知的扩展运算符 (...?),它们提供了一个简洁的方法来向集合中插入多个元素。
举例来说,你可以使用扩展运算符 (...) 来向一个列表中插入另一个列表的所有元素。
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
如果扩展运算符右边的表达式可能为空,你可以使用空感知的扩展运算符来 (...?) 避免异常:
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
要了解更多关于扩展运算符的详情和例子,请参阅 扩展运算符提案。
Dart 2.3 也引入了 集合 if 和 集合 for,它们提供了使用条件 (if) 和循环 (for) 构建结合的方法。
下面是一个使用 集合 if 来创建一个包含3个或4个项目的列表的例子:
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
下面是一个使用 集合 for 在把一个集合的元素插入到另一个集合前操纵它们的例子:
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
要了解更多关于集合 if 和 for 的详情和例子,请参阅 控制流集合提案。
列表类型有许多方便的方法可以用来操作列表。要了解更多内容,请参阅 泛型 和 集合。
Sets
Dart 中的 set 是无序且唯一的元素集合。Dart 通过 set 字面量和 Set 类型来支持 set。
版本说明:尽管 Set 类型一直是 Dart 核心的一部分,set 字面量却是 Dart 2.2 中新引入的。
下面是一个简单的 Dart set,使用字面量创建:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
说明:Dart 推断 halogens 的类型为 Set<String>。如果你试图添加错误的类型到这个 set 中,分析器或运行时会抛出一个错误。要了解更多信息,请参阅 类型推断。
要创建一个空的 set,使用 {} 并提供一个类型参数,或者使用 {} 指向带类型的 Set:
var names = <String>{};
// Set<String> names = {}; // 这样也可以
// var names = {}; // 创建一个 map,而不是 set
Set 还是 map? Map 的字面量语法和 set 的字面量语法很相似。因为 map 字面量的优先级更高,{} 默认表示 Map 类型。如果你忘记了 {} 的类型注解或者它指向的变量,Dart 会创建一个类型为 Map<dynamic, dynamic> 的对象。
使用 add() 或 addAll() 来向已存在的 set 中添加元素:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
使用 .length 来获取 set 中元素的数量:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
要创建一个 set 作为编译期常量,在 set 字面量前使用 const。
final constantSet =
const {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
// constantSet.add('helium'); // 取消这一行的注释会引发一个错误
对于 Dart 2.3,set 支持扩展运算符 (... 和 ...?) 还有集合 if 和集合 for,就像列表那样。要了解更多信息,请参阅 列表 中的相关讨论。
要了解更多关于 set 的信息,请参阅 泛型 和 Set。
Maps
通常来说,映射是一个关联了键和值的对象。键和值都可以是任意类型的对象。“键”是唯一的,但是你可以多次使用相同的“值”。Dart 通过映射字面量和 Map 类型来支持映射。
下面是几个简单的 Dart 映射,使用字面量创建:
var gifts = {
// 键: 值
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
说明:Dart 推断 gifts 拥有类型 Map<String, String>,而 nobleGases 拥有类型 Map<int, String>。如果你试图添加错误的类型到上面的映射中,分析器或者运行时会报告一个错误。要了解更多信息,请参阅 类型推断。
你可以通过 Map 的构造函数创建同样的对象:
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
说明:你可能对 new Map() 这样的形式会更熟悉。在 Dart 2 中,关键词 new 是可选的。详情请参阅 使用构造函数。
添加一个新的键值对到已存在的映射,方法和 JavaScript 一样:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // 添加一个键值对
从映射中取得一个值也和 JavaScript 的写法一样:
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');
如果你查找一个不存在的键,会得到 null:
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
使用 .length 去获得映射中键值对的数量:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
要创建一个作为编译期常量的映射,在映射字面量前加上 const:
final constantMap = const {
2: 'helium',
10: 'neon',
18: 'argon',
};
// constantMap[2] = 'Helium'; // 这一行会引发一个错误
对于 Dart 2.3,映射支持扩展运算符 (... 和 ...?) 还有集合 if 和集合 for,就像列表那样。要了解更多信息,请参阅 列表 中的相关讨论。
要了解更多关于映射的内容,请参阅 泛型 和 Map。
Runes
在 Dart 中,runes 表示字符串中 UTF-32 编码的码位。
Unicode 为世界上所有的书写系统中的每个字母、数字和符号都定义了一个唯一数值。因为 Dart 的字符串是 UTF-16 码位的序列,在字符串中表示32位 Unicode 值需要特殊的语法。
表示一个 Unicode 码位的通常方式是 \uXXXX,其中 XXXX 是一个4位16进制数字。比如,心形符号 (♥) 表示为 \u2665。要指定多于或少于4位的16进制数字,将数字放到花括号里。比如,哈哈笑的 emoji (