目录

dart:core

dart:core 库( API 参考 )提供了一组虽小但却至关重要的内置功能。此库会自动导入到每个 Dart 程序中。

向控制台打印

#

顶级 print() 方法接受单个参数(任何对象),并在控制台中显示该对象的字符串值(由 toString() 返回)。

dart
print(anObject);
print('我喝的是 $tea。');

有关基本字符串和 toString() 的更多信息,请参阅语言教程中的 字符串

数字

#

dart:core 库定义了 num、int 和 double 类,这些类具有一些用于处理数字的基本实用程序。

您可以使用 int 和 double 的 parse() 方法将字符串转换为整数或双精度浮点数:

dart
assert(int.parse('42') == 42);
assert(int.parse('0x42') == 66);
assert(double.parse('0.50') == 0.5);

或者使用 num 的 parse() 方法,如果可能则创建整数,否则创建双精度浮点数:

dart
assert(num.parse('42') is int);
assert(num.parse('0x42') is int);
assert(num.parse('0.50') is double);

要指定整数的基数,请添加 radix 参数:

dart
assert(int.parse('42', radix: 16) == 66);

使用 toString() 方法将 int 或 double 转换为字符串。要指定小数点右边的位数,请使用 toStringAsFixed(). 要指定字符串中的有效数字位数,请使用 toStringAsPrecision():

dart
// 将 int 转换为字符串。
assert(42.toString() == '42');

// 将 double 转换为字符串。
assert(123.456.toString() == '123.456');

// 指定小数点后的位数。
assert(123.456.toStringAsFixed(2) == '123.46');

// 指定有效数字位数。
assert(123.456.toStringAsPrecision(2) == '1.2e+2');
assert(double.parse('1.2e+2') == 120.0);

更多信息,请参阅 int, double,num. 的 API 文档。另请参阅 dart:math 部分

字符串和正则表达式

#

Dart 中的字符串是不可变的 UTF-16 代码单元序列。语言教程包含有关 字符串 的更多信息。您可以使用正则表达式(RegExp 对象)在字符串中搜索并替换字符串的部分内容。

String 类定义了诸如 split()contains()startsWith()endsWith() 等方法。

在字符串内搜索

#

您可以找到字符串内的特定位置,以及检查字符串是否以特定模式开头或结尾。例如:

dart
// 检查字符串是否包含另一个字符串。
assert('Never odd or even'.contains('odd'));

// 字符串是否以另一个字符串开头?
assert('Never odd or even'.startsWith('Never'));

// 字符串是否以另一个字符串结尾?
assert('Never odd or even'.endsWith('even'));

// 查找字符串内字符串的位置。
assert('Never odd or even'.indexOf('odd') == 6);

从字符串中提取数据

#

您可以分别以字符串或整数的形式获取字符串中的各个字符。确切地说,您实际上获得的是单个 UTF-16 代码单元;高编号字符(例如高音谱号符号('\u{1D11E}'))每个包含两个代码单元。

您还可以提取子字符串或将字符串拆分为子字符串列表:

dart
// 获取子字符串。
assert('Never odd or even'.substring(6, 9) == 'odd');

// 使用字符串模式拆分字符串。
var parts = 'progressive web apps'.split(' ');
assert(parts.length == 3);
assert(parts[0] == 'progressive');

// 通过索引获取 UTF-16 代码单元(作为字符串)。
assert('Never odd or even'[0] == 'N');

// 使用空字符串参数调用 split() 以获取所有字符(作为字符串)的列表;适用于迭代。
for (final char in 'hello'.split('')) {
  print(char);
}

// 获取字符串中的所有 UTF-16 代码单元。
var codeUnitList = 'Never odd or even'.codeUnits.toList();
assert(codeUnitList[0] == 78);

::: 在许多情况下,您希望使用 Unicode 音素群,而不是纯代码单元。这些字符是用户感知到的字符(例如,“🇬🇧”是一个用户感知的字符,但包含多个 UTF-16 代码单元)。为此,Dart 团队提供了 characters 包。 :::

转换为大写或小写

#

您可以轻松地将字符串转换为其大写和小写变体:

dart
// 转换为大写。
assert('web apps'.toUpperCase() == 'WEB APPS');

// 转换为小写。
assert('WEB APPS'.toLowerCase() == 'web apps');

修剪和空字符串

#

使用 trim() 删除所有前导和尾随空格。要检查字符串是否为空(长度为零),请使用 isEmpty

dart
// 修剪字符串。
assert('  hello  '.trim() == 'hello');

// 检查字符串是否为空。
assert(''.isEmpty);

// 仅包含空格的字符串不为空。
assert('  '.isNotEmpty);

替换字符串的一部分

#

字符串是不可变的对象,这意味着您可以创建它们,但不能更改它们。如果您仔细查看 String API 参考, 您会注意到,没有一种方法会实际更改 String 的状态。例如, replaceAll() 方法返回一个新 String,而不会更改原始 String:

dart
var greetingTemplate = 'Hello, NAME!';
var greeting = greetingTemplate.replaceAll(RegExp('NAME'), 'Bob');

// greetingTemplate 没有改变。
assert(greeting != greetingTemplate);

构建字符串

#

要以编程方式生成字符串,可以使用 StringBuffer。在调用 toString() 之前,StringBuffer 不会生成新的 String 对象。 writeAll() 方法有一个可选的第二个参数,允许您指定分隔符——在本例中为空格。

dart
var sb = StringBuffer();
sb
  ..write('Use a StringBuffer for ')
  ..writeAll(['efficient', 'string', 'creation'], ' ')
  ..write('.');

var fullString = sb.toString();

assert(fullString == 'Use a StringBuffer for efficient string creation.');

正则表达式

#

RegExp 类提供了与 JavaScript 正则表达式相同的功能。使用正则表达式可以有效地搜索和匹配字符串的模式。

dart
// 这是一个或多个数字的正则表达式。
var numbers = RegExp(r'\d+');

var allCharacters = 'llamas live fifteen to twenty years';
var someDigits = 'llamas live 15 to 20 years';

// contains() 可以使用正则表达式。
assert(!allCharacters.contains(numbers));
assert(someDigits.contains(numbers));

// 将每个匹配项替换为另一个字符串。
var exedOut = someDigits.replaceAll(numbers, 'XX');
assert(exedOut == 'llamas live XX to XX years');

您也可以直接使用 RegExp 类。Match 类提供对正则表达式匹配的访问。

dart
var numbers = RegExp(r'\d+');
var someDigits = 'llamas live 15 to 20 years';

// 检查正则表达式在字符串中是否有匹配项。
assert(numbers.hasMatch(someDigits));

// 循环遍历所有匹配项。
for (final match in numbers.allMatches(someDigits)) {
  print(match.group(0)); // 15,然后是 20
}

更多信息

#

有关方法的完整列表,请参阅 String API 参考 。另请参阅 StringBuffer, Pattern, RegExp,Match. 的 API 参考

集合

#

Dart 附带核心集合 API,其中包括用于列表、集合和映射的类。

列表

#

正如语言教程所示,您可以使用文字来创建和初始化 列表 。或者,使用 List 构造函数之一。List 类还定义了若干方法,用于向列表中添加项目和从列表中删除项目。

dart
// 创建一个空的字符串列表。
var grains = <String>[];
assert(grains.isEmpty);

// 使用列表文字创建列表。
var fruits = ['apples', 'oranges'];

// 添加到列表。
fruits.add('kiwis');

// 向列表中添加多个项目。
fruits.addAll(['grapes', 'bananas']);

// 获取列表长度。
assert(fruits.length == 5);

// 删除单个项目。
var appleIndex = fruits.indexOf('apples');
fruits.removeAt(appleIndex);
assert(fruits.length == 4);

// 从列表中删除所有元素。
fruits.clear();
assert(fruits.isEmpty);

// 您还可以使用其中一个构造函数创建 List。
var vegetables = List.filled(99, 'broccoli');
assert(vegetables.every((v) => v == 'broccoli'));

使用 indexOf() 查找列表中对象的索引:

dart
var fruits = ['apples', 'oranges'];

// 通过索引访问列表项。
assert(fruits[0] == 'apples');

// 在列表中查找项目。
assert(fruits.indexOf('apples') == 0);

使用 sort() 方法对列表进行排序。您可以提供一个比较两个对象的排序函数。此排序函数必须返回 < 0 表示 较小、0 表示 相同 和 > 0 表示 较大。以下示例使用 compareTo() ,它由 Comparable 定义并由 String 实现。

dart
var fruits = ['bananas', 'apples', 'oranges'];

// 对列表进行排序。
fruits.sort((a, b) => a.compareTo(b));
assert(fruits[0] == 'apples');

列表是参数化类型( 泛型 ),因此您可以指定列表应包含的类型:

dart
// 此列表应仅包含字符串。
var fruits = <String>[];

fruits.add('apples');
var fruit = fruits[0];
assert(fruit is String);
✗ static analysis: failuredart
fruits.add(5); // 错误:无法将 'int' 分配给 'String'

有关方法的完整列表,请参阅 List API 参考

集合

#

Dart 中的集合是唯一项目的无序集合。因为集合是无序的,所以您不能按索引(位置)获取集合的项目。

dart
// 创建一个空的字符串集合。
var ingredients = <String>{};

// 向其中添加新项目。
ingredients.addAll(['gold', 'titanium', 'xenon']);
assert(ingredients.length == 3);

// 添加重复项无效。
ingredients.add('gold');
assert(ingredients.length == 3);

// 从集合中删除项目。
ingredients.remove('gold');
assert(ingredients.length == 2);

// 您还可以使用构造函数之一创建集合。
var atomicNumbers = Set.from([79, 22, 54]);

使用 contains()containsAll() 检查集合中是否存在一个或多个对象:

dart
var ingredients = Set<String>();
ingredients.addAll(['gold', 'titanium', 'xenon']);

// 检查集合中是否存在项目。
assert(ingredients.contains('titanium'));

// 检查集合中是否包含所有项目。
assert(ingredients.containsAll(['titanium', 'xenon']));

交集是一个其项目存在于其他两个集合中的集合。

dart
var ingredients = Set<String>();
ingredients.addAll(['gold', 'titanium', 'xenon']);

// 创建两个集合的交集。
var nobleGases = Set.from(['xenon', 'argon']);
var intersection = ingredients.intersection(nobleGases);
assert(intersection.length == 1);
assert(intersection.contains('xenon'));

有关方法的完整列表,请参阅 Set API 参考

映射

#

映射,通常称为 字典哈希,是键值对的无序集合。映射将键与某个值关联起来,以便于检索。与 JavaScript 不同,Dart 对象不是映射。

您可以使用简洁的文字语法声明映射,也可以使用传统的构造函数:

dart
// 映射通常使用字符串作为键。
var hawaiianBeaches = {
  'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  'Big Island': ['Wailea Bay', 'Pololu Beach'],
  'Kauai': ['Hanalei', 'Poipu']
};

// 可以从构造函数构建映射。
var searchTerms = Map();

// 映射是参数化类型;您可以指定键和值应该是什么类型。
var nobleGases = Map<int, String>();

您可以使用方括号语法添加、获取和设置映射项。使用 remove() 从映射中删除键及其值。

dart
var nobleGases = {54: 'xenon'};

// 使用键检索值。
assert(nobleGases[54] == 'xenon');

// 检查映射是否包含键。
assert(nobleGases.containsKey(54));

// 删除键及其值。
nobleGases.remove(54);
assert(!nobleGases.containsKey(54));

您可以从映射中检索所有值或所有键:

dart
var hawaiianBeaches = {
  'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  'Big Island': ['Wailea Bay', 'Pololu Beach'],
  'Kauai': ['Hanalei', 'Poipu']
};

// 获取所有键作为无序集合(Iterable)。
var keys = hawaiianBeaches.keys;

assert(keys.length == 3);
assert(Set.from(keys).contains('Oahu'));

// 获取所有值作为无序集合(列表的 Iterable)。
var values = hawaiianBeaches.values;
assert(values.length == 3);
assert(values.any((v) => v.contains('Waikiki')));

要检查映射是否包含键,请使用 containsKey() 。因为映射值可以为 null,所以您不能仅仅依靠获取键的值并检查 null 来确定键是否存在。

dart
var hawaiianBeaches = {
  'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  'Big Island': ['Wailea Bay', 'Pololu Beach'],
  'Kauai': ['Hanalei', 'Poipu']
};

assert(hawaiianBeaches.containsKey('Oahu'));
assert(!hawaiianBeaches.containsKey('Florida'));

当您只想在键尚不存在于映射中时才将值分配给键时,请使用 putIfAbsent() 方法。您必须提供一个返回该值的函数。

dart
var teamAssignments = <String, String>{};
teamAssignments.putIfAbsent('Catcher', () => pickToughestKid());
assert(teamAssignments['Catcher'] != null);

有关方法的完整列表,请参阅 Map API 参考

常用集合方法

#

List、Set 和 Map 共享许多集合中存在的常用功能。一些常用功能由 List 和 Set 实现的 Iterable 类定义。

使用 isEmptyisNotEmpty 检查列表、集合或映射中是否有项目:

dart
var coffees = <String>[];
var teas = ['green', 'black', 'chamomile', 'earl grey'];
assert(coffees.isEmpty);
assert(teas.isNotEmpty);

要将函数应用于列表、集合或映射中的每个项目,您可以使用 forEach()

dart
var teas = ['green', 'black', 'chamomile', 'earl grey'];

teas.forEach((tea) => print('我喝的是 $tea'));

当您在映射上调用 forEach() 时,您的函数必须接受两个参数(键和值):

dart
hawaiianBeaches.forEach((k, v) {
  print('我想去 $k 游览并在 $v 游泳');
  // 我想去 Oahu 游览并在 [Waikiki, Kailua, Waimanalo] 等地游泳。
});

Iterable 提供 map() 方法,该方法可在单个对象中提供所有结果:

dart
var teas = ['green', 'black', 'chamomile', 'earl grey'];

var loudTeas = teas.map((tea) => tea.toUpperCase());
loudTeas.forEach(print);

要强制立即对每个项目调用您的函数,请使用 map().toList()map().toSet()

dart
var loudTeas = teas.map((tea) => tea.toUpperCase()).toList();

使用 Iterable 的 where() 方法获取满足条件的所有项目。使用 Iterable 的 any()every() 方法检查某些或所有项目是否满足条件。

dart
var teas = ['green', 'black', 'chamomile', 'earl grey'];

// 洋甘菊不含咖啡因。
bool isDecaffeinated(String teaName) => teaName == 'chamomile';

// 使用 where() 仅查找从提供的函数返回 true 的项目。
var decaffeinatedTeas = teas.where((tea) => isDecaffeinated(tea));
// 或 teas.where(isDecaffeinated)

// 使用 any() 检查集合中至少一个项目是否满足条件。
assert(teas.any(isDecaffeinated));

// 使用 every() 检查集合中所有项目是否满足条件。
assert(!teas.every(isDecaffeinated));

有关方法的完整列表,请参阅 Iterable API 参考, 以及 List, Set,Map。 的 API 参考

URI

#

Uri 类 提供了用于编码和解码字符串以在 URI(您可能将其称为 URL)中使用的函数。这些函数处理对 URI 具有特殊意义的字符,例如 &= 。Uri 类还解析并公开 URI 的组件——主机、端口、方案等等。

编码和解码完全限定的 URI

#

要编码和解码 URI 中具有特殊含义的字符(例如 /:&# )之外的字符,请使用 encodeFull()decodeFull() 方法。这些方法非常适合编码或解码完全限定的 URI,同时保持特殊 URI 字符不变。

dart
var uri = 'https://example.org/api?foo=some message';

var encoded = Uri.encodeFull(uri);
assert(encoded == 'https://example.org/api?foo=some%20message');

var decoded = Uri.decodeFull(encoded);
assert(uri == decoded);

请注意,只有 somemessage 之间的空格被编码了。

编码和解码 URI 组件

#

要编码和解码 URI 中具有特殊含义的所有字符串字符,包括(但不限于) /&: ,请使用 encodeComponent()decodeComponent() 方法。

dart
var uri = 'https://example.org/api?foo=some message';

var encoded = Uri.encodeComponent(uri);
assert(
    encoded == 'https%3A%2F%2Fexample.org%2Fapi%3Ffoo%3Dsome%20message');

var decoded = Uri.decodeComponent(encoded);
assert(uri == decoded);

请注意,每个特殊字符都已编码。例如, / 编码为 %2F

解析 URI

#

如果您有 Uri 对象或 URI 字符串,则可以使用 Uri 字段(例如 path )获取其各个部分。要从字符串创建 Uri,请使用 parse() 静态方法:

dart
var uri = Uri.parse('https://example.org:8080/foo/bar#frag');

assert(uri.scheme == 'https');
assert(uri.host == 'example.org');
assert(uri.path == '/foo/bar');
assert(uri.fragment == 'frag');
assert(uri.origin == 'https://example.org:8080');

请参阅 Uri API 参考 ,了解您可以获取的更多 URI 组件。

构建 URI

#

您可以使用 Uri() 构造函数从各个部分构建 URI:

dart
var uri = Uri(
    scheme: 'https',
    host: 'example.org',
    path: '/foo/bar',
    fragment: 'frag',
    queryParameters: {'lang': 'dart'});
assert(uri.toString() == 'https://example.org/foo/bar?lang=dart#frag');

如果您不需要指定片段,要创建一个具有 http 或 https 方案的 URI,您可以改为使用 Uri.httpUri.https 工厂构造函数:

dart
var httpUri = Uri.http('example.org', '/foo/bar', {'lang': 'dart'});
var httpsUri = Uri.https('example.org', '/foo/bar', {'lang': 'dart'});

assert(httpUri.toString() == 'http://example.org/foo/bar?lang=dart');
assert(httpsUri.toString() == 'https://example.org/foo/bar?lang=dart');

日期和时间

#

DateTime 对象是一个时间点。时区是 UTC 或本地时区。

本地时区。

您可以使用多个构造函数和方法创建 DateTime 对象:

dart
// 获取当前日期和时间。
var now = DateTime.now();

// 使用本地时区创建一个新的 DateTime。
var y2k = DateTime(2000); // 2000年1月1日

// 指定月份和日期。
y2k = DateTime(2000, 1, 2); // 2000年1月2日

// 将日期指定为 UTC 时间。
y2k = DateTime.utc(2000); // 2000年1月1日,UTC

// 指定自 Unix 纪元以来的毫秒数的日期和时间。
y2k = DateTime.fromMillisecondsSinceEpoch(946684800000, isUtc: true);

// 解析 UTC 时区的 ISO 8601 日期。
y2k = DateTime.parse('2000-01-01T00:00:00Z');

// 从现有 DateTime 创建一个新的 DateTime,只调整一些属性:
var sameTimeLastYear = now.copyWith(year: now.year - 1);

日期的 millisecondsSinceEpoch 属性返回自“Unix 纪元”(1970年1月1日,UTC)以来的毫秒数:

dart
// 2000年1月1日,UTC
var y2k = DateTime.utc(2000);
assert(y2k.millisecondsSinceEpoch == 946684800000);

// 1970年1月1日,UTC
var unixEpoch = DateTime.utc(1970);
assert(unixEpoch.millisecondsSinceEpoch == 0);

使用 Duration 类计算两个日期之间的差值,并将日期向前或向后移动:

dart
var y2k = DateTime.utc(2000);

// 添加一年。
var y2001 = y2k.add(const Duration(days: 366));
assert(y2001.year == 2001);

// 减去 30 天。
var december2000 = y2001.subtract(const Duration(days: 30));
assert(december2000.year == 2000);
assert(december2000.month == 12);

// 计算两个日期之间的差值。
// 返回 Duration 对象。
var duration = y2001.difference(y2k);
assert(duration.inDays == 366); // y2k 是闰年。

有关方法的完整列表,请参阅 DateTimeDuration 的 API 参考。

实用程序类

#

核心库包含各种实用程序类,可用于排序、映射值和迭代。

比较对象

#

实现 Comparable 接口以指示可以将对象与另一个对象进行比较,通常用于排序。 compareTo() 方法返回 < 0 表示 较小、0 表示 相同 和 > 0 表示 较大

dart
class Line implements Comparable<Line> {
  final int length;
  const Line(this.length);

  @override
  int compareTo(Line other) => length - other.length;
}

void main() {
  var short = const Line(1);
  var long = const Line(100);
  assert(short.compareTo(long) < 0);
}

实现映射键

#

Dart 中的每个对象都自动提供一个整数哈希码,因此可以用作映射中的键。但是,您可以重写 hashCode getter 来生成自定义哈希码。如果这样做,您可能还需要重写 == 运算符。相等的(通过 == )对象必须具有相同的哈希码。哈希码不必唯一,但应该分布良好。

dart
class Person {
  final String firstName, lastName;

  Person(this.firstName, this.lastName);

  // 使用 `Object` 类提供的静态哈希方法重写 hashCode。
  @override
  int get hashCode => Object.hash(firstName, lastName);

  // 如果重写 `hashCode` ,通常应该实现运算符 `==` 。
  @override
  bool operator ==(Object other) {
    return other is Person &&
        other.firstName == firstName &&
        other.lastName == lastName;
  }
}

void main() {
  var p1 = Person('Bob', 'Smith');
  var p2 = Person('Bob', 'Smith');
  var p3 = 'not a person';
  assert(p1.hashCode == p2.hashCode);
  assert(p1 == p2);
  assert(p1 != p3);
}

迭代

#

IterableIterator 类支持对值集合的顺序访问。要练习使用这些集合,请遵循 Iterable 集合教程

如果您创建了一个可以为 for-in 循环提供迭代器的类,则扩展(如果可能)或实现 Iterable。实现 Iterator 以定义实际的迭代能力。

dart
class Process {
  // 代表一个进程……
}

class ProcessIterator implements Iterator<Process> {
  @override
  Process get current => ...
  @override
  bool moveNext() => ...
}

// 一个虚构的类,允许您遍历所有进程。扩展 [Iterable] 的子类。
class Processes extends IterableBase<Process> {
  @override
  final Iterator<Process> iterator = ProcessIterator();
}

void main() {
  // Iterable 对象可以与 for-in 一起使用。
  for (final process in Processes()) {
    // 对进程执行某些操作。
  }
}

异常

#

Dart 核心库定义了许多常见的异常和错误。异常被认为是可以提前计划和捕获的条件。错误是您不期望或计划的条件。

一些最常见的错误是:

NoSuchMethodError :当接收对象(可能是 null )未实现方法时抛出。

ArgumentError :可以由遇到意外参数的方法抛出。

抛出应用程序特定的异常是指示发生错误的一种常用方法。您可以通过实现 Exception 接口来定义自定义异常:

dart
class FooException implements Exception {
  final String? msg;

  const FooException([this.msg]);

  @override
  String toString() => msg ?? 'FooException';
}

有关更多信息,请参阅 异常 (在语言教程中)和 Exception API 参考。

弱引用和终结器

#

Dart 是一种 垃圾回收 语言,这意味着任何未被引用的 Dart 对象都可以由垃圾回收器释放。在涉及本地资源的某些情况下,或者如果目标对象无法修改,这种默认行为可能并不理想。

WeakReference 存储对目标对象的引用,但这不会影响垃圾回收器如何收集它。另一种选择是使用 Expando 向对象添加属性。

Finalizer 可用于在不再引用对象后执行回调函数。但是,不能保证执行此回调。

NativeFinalizer 为使用 dart:ffi 与本机代码交互提供了更强的保证;在不再引用对象之后,其回调至少被调用一次。此外,它还可用于关闭本机资源,例如数据库连接或打开的文件。

为了确保对象不会过早地被垃圾回收和终结,类可以实现 Finalizable 接口。当局部变量是 Finalizable 时,它不会被垃圾回收,直到声明它的代码块退出。