05.Dart内置类型

·  阅读 60

内置类型

Dart 语言支持下列内容:

使用字面量来创建对象也受到支持。例如 'This is a string' 是一个字符串字面量,true 是一个布尔字面量。

由于 Dart 中每个变量引用都指向一个对象(一个  的实例),通常也可以使用 构造器 来初始化变量。一些内置的类型有它们自己的构造器。例如你可以使用 Map() 来创建一个 map 对象。

其他类型在Dart语言中也有特殊的作用:

  • Object:所有Dart类的超类,除了Null。
  • Future和Stream:用于异步支持。
  • Iterable:用于for-in循环和同步生成器函数中。
  • Never:表示表达式永远不能成功地完成求值。最常用于总是抛出异常的函数。
  • dynamic:关闭静态检查。通常你应该使用Object或Object?代替。
  • void:表示某个值从未被使用。通常用作返回类型。

Numbers

Dart 支持两种 Number 类型:

  • int

    整数值;长度不超过 64 位,具体取值范围 依赖于不同的平台。在 DartVM 上其取值位于 -263 至 263 - 1 之间。在 Web 上,整型数值代表着 JavaScript 的数字(64 位无小数浮点型),其允许的取值范围在 -253 至 253 - 1 之间。

  • double

    64 位的双精度浮点数字,且符合 IEEE 754 标准。

int 和 double 都是 [num][num] 的子类。 num 中定义了一些基本的运算符比如 +、-、*、/ 等,还定义了 abs()ceil() 和 floor() 等方法(位运算符,比如 >> 定义在 int 中)。如果 num 及其子类不满足你的要求,可以查看 dart:math 库中的 API。

整数是不带小数点的数字,下面是一些定义整数字面量的例子:

var x = 1;
var hex = 0xDEADBEEF;
var exponent = 8e5;
复制代码

如果一个数字包含了小数点,那么它就是浮点型的。下面是一些定义浮点数字面量的例子:

var y = 1.1;
var exponents = 1.42e5;
复制代码

还可以将变量声明为num,如果您这样做,该变量可以同时具有整型和双精度值

num x = 1; // x可以同时具有int和double值
x += 2.5;
复制代码

整型字面量将会在必要的时候自动转换成浮点数字面量:

double z = 1; // 相当于 double z = 1.0.
复制代码

在 Dart 2.1 之前,在浮点数上下文中使用整数字面量是错误的。
更多内容,请查看 Dart 中的数字

Strings

Dart 字符串(String 对象)包含了 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.";
复制代码

在字符串中,请以 ${表达式} 的形式使用表达式,如果表达式是一个标识符,可以省略掉 {}。如果表达式的结果为一个对象,则 Dart 会调用该对象的 toString 方法来获取一个字符串。

// 代码解释
var s = '字符串插值';
assert('Dart 有$s,使用起来非常方便。' == 'Dart 有字符串插值,使用起来非常方便。');
assert('使用${s.substring(3,5)}表达式也非常方便' == '使用插值表达式也非常方便。');
复制代码

== 运算符负责判断两个对象的内容是否一样,如果两个字符串包含一样的字符编码序列,则表示相等。
你可以使用 + 运算符或并列放置多个字符串来连接字符串:

// 代码解释
var s1 = '可以拼接'
    '字符串'
    "即便它们不在同一行。";
print(s1 == '可以拼接字符串即便它们不在同一行。');

var s2 = '使用加号 + 运算符' + '也可以达到相同的效果。';
print(s2 == '使用加号 + 运算符也可以达到相同的效果。');
复制代码

使用三个单引号或者三个双引号也能创建多行字符串:

// 代码解释
  var s5 = '''你可以像这样创建多行字符串''';
  var s6 = """你可以像这样创建多行字符串""";
  print(s5 == s6); // true
复制代码

在字符串前加上 r 作为前缀创建 “raw” 字符串(即不会被做任何处理(比如转义)的字符串):

var s = r'在 raw 字符串中,转义字符串 \n 会直接输出 “\n” 而不是转义为换行。';
print(s); // 在 raw 字符串中,转义字符串 \n 会直接输出 “\n” 而不是转义为换行。\
复制代码

你可以查阅 Runes 与 grapheme clusters 获取更多关于如何在字符串中表示 Unicode 字符的信息。

字符串字面量是一个编译时常量,只要是编译时常量 (null、数字、字符串、布尔) 都可以作为字符串字面量的插值表达式:

// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// These do NOT work in a const 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) 或者 assert (nonbooleanValue) 这样的代码检查布尔值。相反,你应该总是显示地检查布尔值,比如像下面的代码这样:

// 检查空字符串。
var fullName = '';
print(fullName.isEmpty); // true

// 检查 0 值。
var hitPoints = 0;
print(hitPoints <= 0); // true

// 检查 null 值。
var unicorn;
print(unicorn == null); // true

// 检查 NaN 。
var iMeantToDoThis = 0 / 0;
print(iMeantToDoThis.isNaN); // true
复制代码

Lists

数组 (Array) 是几乎所有编程语言中最常见的集合类型,在 Dart 中数组由 List 对象表示。通常称之为 List

Dart 中 List 字面量看起来与 JavaScript 中数组字面量一样。下面是一个 Dart List 的示例:

var list = [1, 2, 3];
复制代码

这里 Dart 推断出 list 的类型为 List<int>,如果往该数组中添加一个非 int 类型的对象则会报错。你可以阅读 类型推断 获取更多相关信息。

你可以在 Dart 的集合类型的最后一个项目后添加逗号。这个尾随逗号并不会影响集合,但它能有效避免「复制粘贴」的错误。

var list = ['Car','Boat','Plane',];
复制代码

List 的下标索引从 0 开始,第一个元素的下标为 0,最后一个元素的下标为 list.length - 1。你可以像 JavaScript 中的用法那样获取 Dart 中 List 的长度以及元素:

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);
复制代码

在 List 字面量前添加 const 关键字会创建一个编译时常量:

var constantList = const [1, 2, 3];
// constantList[1] = 1; // This line will cause an error.
复制代码

创建final实例变量,final对象不能被修改,但是它的字段可以被修改:

final list = [1, 2, 3];
var constantList = list;
constantList[1] = 1; 
print(constantList); // [1, 1, 3]
复制代码

list应用扩展操作符 ......?

Dart 在 2.3 引入了 扩展操作符...)和 空感知扩展操作符...?),它们提供了一种将多个元素插入集合的简洁方法。
你可以使用扩展操作符(...)将一个 List 中的所有元素插入到另一个 List 中:

var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
复制代码

如果扩展操作符右边可能为 null ,你可以使用 null-aware 扩展操作符(...?)来避免产生异常:

var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
复制代码

可以查阅扩展操作符建议获取更多关于如何使用扩展操作符的信息。

Dart 还同时引入了 集合中的 if 和 集合中的 for 操作,在构建集合时,可以使用条件判断 (if) 和循环 (for)。

下面示例是使用 集合中的 if 来创建一个 List 的示例,它可能包含 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 的细节内容和示例。

List 类中有许多用于操作 List 的便捷方法,你可以查阅 泛型 和 集合 获取更多与之相关的信息。

Sets

在 Dart 中,set 是一组元素唯一的无序集合。 Dart 支持的集合由集合的字面量和 Set 类提供。

尽管 Set 类型(type)  一直都是 Dart 的一项核心功能,但是 Set 字面量(literals)  是在 Dart 2.2 中才加入的。

下面是使用 Set 字面量来创建一个 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 变量前添加 const 关键字创建一个 Set 编译时常量:

final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // This line will cause an error.
复制代码

从 Dart 2.3 开始,Set 可以像 List 一样支持使用扩展操作符(... 和 ...?)以及 Collection if 和 for 操作。你可以查阅 List 扩展操作符 和 List 集合操作符 获取更多相关信息。

你也可以查阅 泛型 以及 Set 获取更多相关信息。

Maps

通常来说,Map 是用来关联 keys 和 values 的对象。其中键和值都可以是任何类型的对象。每个  只能出现一次但是  可以重复出现多次。 Dart 中 Map 提供了 Map 字面量以及 Map 类型两种形式的 Map。

下面是一对使用 Map 字面量创建 Map 的例子:

var gifts = {
    // Key:    Value
    '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 对象中添加不正确的类型值,将导致运行时异常。你可以阅读 类型推断 获取更多相关信息。

你也可以使用 Map 的构造器创建 Map:

var gifts = Map<String, String>();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map<int, String>();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
复制代码

如果你之前是使用的 C# 或 Java 这样的语言,也许你想使用 new Map() 构造 Map 对象。但是在 Dart 中,new 关键词是可选的。(且不被建议使用) 你可以查阅 构造函数的使用 获取更多相关信息。

向现有的 Map 中添加键值对与 JavaScript 的操作类似:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair
复制代码

从一个 Map 中获取一个值的操作也与 JavaScript 类似:

var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');
复制代码

如果检索的 Key 不存在于 Map 中则会返回一个 null:

var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
复制代码

使用 .length 可以获取 Map 中键值对的数量:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
复制代码

在一个 Map 字面量前添加 const 关键字可以创建一个 Map 编译时常量:

final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

// constantMap[2] = 'Helium'; // This line will cause an error.
复制代码

Map 可以像 List 一样支持使用扩展操作符(... 和 ...?)以及集合的 if 和 for 操作。你可以查阅 List 扩展操作符 和 List 集合操作符 获取更多相关信息。

你也可以查阅 泛型 以及 Maps API 获取更多相关信息。

Runes 与 grapheme clusters

在 Dart 中,runes 公开了字符串的 Unicode 码位。使用 characters 包 来访问或者操作用户感知的字符,也被称为 Unicode (扩展) grapheme clusters

Unicode 编码为每一个字母、数字和符号都定义了一个唯一的数值。因为 Dart 中的字符串是一个 UTF-16 的字符序列,所以如果想要表示 32 位的 Unicode 数值则需要一种特殊的语法。

表示 Unicode 字符的常见方式是使用 \uXXXX,其中 XXXX 是一个四位数的 16 进制数字。例如心形字符(♥)的 Unicode 为 \u2665。对于不是四位数的 16 进制数字,需要使用大括号将其括起来。例如大笑的 emoji 表情(😆)的 Unicode 为 \u{1f600}

如果你需要读写单个 Unicode 字符,可以使用 characters 包中定义的 characters getter。它将返回 Characters 对象作为一系列 grapheme clusters 的字符串。下面是使用 characters API 的样例:

import 'package:characters/characters.dart';
...
var hi = 'Hi 🇩🇰';
print(hi);
print('The end of the string: ${hi.substring(hi.length - 1)}');
print('The last character: ${hi.characters.last}\n');
复制代码

输出取决于你的环境,大致类似于:

$ dart run bin/main.dart
Hi 🇩🇰
The end of the string: ???
The last character: 🇩🇰
复制代码

有关使用 characters 包操作字符串的详细信息,请参阅用于 characters 包的样例 和 API 参考

在使用 List 操作 Rune 的时候需要小心,根据所操作的语种、字符集等不同可能会导致字符串出现问题,具体可参考 Stack Overflow 中的提问: [我如何在 Dart 中反转一个字符串?][How do I reverse a String in Dart?]。

Symbols

Symbol 表示 Dart 中声明的操作符或者标识符。你几乎不会需要 Symbol,但是它们对于那些通过名称引用标识符的 API 很有用,因为代码压缩后,尽管标识符的名称会改变,但是它们的 Symbol 会保持不变。

可以使用在标识符前加 # 前缀来获取 Symbol:

#radix
#bar
复制代码

Symbol 字面量是编译时常量。

分类:
前端
标签: