Dart

Dart - 内置类型(List、Set、Map、Runes)

2019-12-09  本文已影响0人  LouisXWB

这节继续学习Dart的内置类型,List、Set和Map。

list

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

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

var list = [1, 2, 3];

这里 Dart 推断出list 的类型为 List<int>,如果往该数组中添加一个非 int 类型的对象则会报错。

如果想要创建一个编译时常量的 List,在 List 字面量前添加 const关键字即可:

var constantList = const [1, 2, 3];
// 取消注释将导致出错 (Uncommenting this causes an error.)
// constantList[1] = 1; 

Dart 在 2.3 引入了 扩展操作符(...)和 null-aware 扩展操作符(...?),它们提供了一种将多个元素插入集合的简洁方法。
例如,你可以使用扩展操作符(...)将一个 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 在 2.3 还同时引入了 Collection IfCollection For,在构建集合时,可以使用条件判断(if)和循环(for)。

下面示例是使用 Collection If 来创建一个 List 的示例,它可能包含 3 个或 4 个元素:

var nav = [
  'Home',
  'Furniture',
  'Plants',
  if (promoActive) 'Outlet'
];

下面示例是使用 Collection For 将列表中的元素修改后添加到另一个列表中的示例:

var listOfInts = [1, 2, 3];
var listOfStrings = [
  '#0',
  for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');

Set

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

下面是使用 Set 字面量来创建一个 Set 集合的方法:

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

可以使用在 {} 前加上类型参数的方式创建一个空的 Set,或者将 {} 赋值给一个 Set 类型的变量:

var names = <String>{}; // 类型+{}的形式创建Set。
// 声明类型变量的形式创建 Set (This works, too).
// Set<String> names = {}; 
// var names = {}; 
// 这样的形式将创建一个 Map 而不是 Set (Creates a map, not a set.)

疑问:用{}声明返回的是Set 还是 map?
⚠️:" Map 字面量语法同 Set 字面量语法非常相似。因为是先有的 Map 字面量语法,所以 {} 默认是 Map 类型。如果忘记在 {} 上注释类型或赋值到一个未声明类型的变量上,那么 Dart 会创建一个类型为 Map<dynamic, dynamic> 的对象。"

向一个已存在的 Set 中添加项目可以使用 add() 方法或 addAll() 方法:

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');
 // 取消注释将导致出错 (Uncommenting this causes an error).

从 Dart 2.3 开始,Set 可以像 List 一样支持使用扩展操作符(... 和 ...?)以及 Collection IfCollection For 操作。

Map

Dart 中 Map 通过 Map 字面量和 Map 类型来实现,下面是一对使用 Map 字面量创建 Map 的例子:

var gifts = {
  // 键:    值
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

gifts的类型推断为Map<String, String>,而 nobleGases 的类型推断为 Map<int, String>。如果你向这两个 Map 对象中添加不正确的类型值,将导致运行时异常。

你也可以使用 Map 的构造器创建 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';

疑问:这里为什么使用 Map() 而不是使用 new Map() 构造 Map 对象?
⚠️:因为从Dart2 开始,构造对象的 new 关键字可以被省略掉。

从 Dart 2.3 Map 也可以像 List 一样支持使用扩展操作符(... 和 ...?)以及 Collection IfCollection For 操作。

Runes

Dart 使用 Runes 符文来表示 UTF-32 编码的字符串。

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

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

String 类中有一些属性可以用来提取字符串的 Rune 符文信息。codeUnitAtcodeUnit 属性返回 16 位代码单元。runes 属性可以获取字符串的 Runes 符文。

下面的例子说明了 Rune、16位代码单元、32位代码单元之间的关系:

  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));

Console:

👏
[55357, 56399]
[128079]
♥  😅  😎  👻  🖖  👍

⚠️备忘
在使用 List 操作 Rune 的时候需要小心,根据所操作的语种、字符集等不同可能会导致字符串出现问题,具体可参考 Stack Overflow 中的提问: 我如何在 Dart 中反转一个字符串?

上一篇下一篇

猜你喜欢

热点阅读