内容

dart:core

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

打印到控制台

#

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

dart
print(anObject);
print('I drink $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
// Convert an int to a string.
assert(42.toString() == '42');

// Convert a double to a string.
assert(123.456.toString() == '123.456');

// Specify the number of digits after the decimal.
assert(123.456.toStringAsFixed(2) == '123.46');

// Specify the number of significant figures.
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
// Check whether a string contains another string.
assert('Never odd or even'.contains('odd'));

// Does a string start with another string?
assert('Never odd or even'.startsWith('Never'));

// Does a string end with another string?
assert('Never odd or even'.endsWith('even'));

// Find the location of a string inside a string.
assert('Never odd or even'.indexOf('odd') == 6);

从字符串中提取数据

#

你可以分别将字符串中的单个字符作为 Strings 或 ints 获取。准确地说,你实际上获取的是单个 UTF-16 代码单元;高编号字符(如高音谱号符号('\u{1D11E}'))包含两个代码单元。

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

dart
// Grab a substring.
assert('Never odd or even'.substring(6, 9) == 'odd');

// Split a string using a string pattern.
var parts = 'progressive web apps'.split(' ');
assert(parts.length == 3);
assert(parts[0] == 'progressive');

// Get a UTF-16 code unit (as a string) by index.
assert('Never odd or even'[0] == 'N');

// Use split() with an empty string parameter to get
// a list of all characters (as Strings); good for
// iterating.
for (final char in 'hello'.split('')) {
  print(char);
}

// Get all the UTF-16 code units in the string.
var codeUnitList = 'Never odd or even'.codeUnits.toList();
assert(codeUnitList[0] == 78);

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

转换为大写或小写

#

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

dart
// Convert to uppercase.
assert('web apps'.toUpperCase() == 'WEB APPS');

// Convert to lowercase.
assert('WEB APPS'.toLowerCase() == 'web apps');

修剪和空字符串

#

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

dart
// Trim a string.
assert('  hello  '.trim() == 'hello');

// Check whether a string is empty.
assert(''.isEmpty);

// Strings with only white space are not empty.
assert('  '.isNotEmpty);

替换字符串的一部分

#

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

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

// greetingTemplate didn't change.
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
// Here's a regular expression for one or more digits.
var numbers = RegExp(r'\d+');

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

// contains() can use a regular expression.
assert(!allCharacters.contains(numbers));
assert(someDigits.contains(numbers));

// Replace every match with another string.
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';

// Check whether the reg exp has a match in a string.
assert(numbers.hasMatch(someDigits));

// Loop through all matches.
for (final match in numbers.allMatches(someDigits)) {
  print(match.group(0)); // 15, then 20
}

更多信息

#

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

集合

#

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

列表

#

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

dart
// Create an empty list of strings.
var grains = <String>[];
assert(grains.isEmpty);

// Create a list using a list literal.
var fruits = ['apples', 'oranges'];

// Add to a list.
fruits.add('kiwis');

// Add multiple items to a list.
fruits.addAll(['grapes', 'bananas']);

// Get the list length.
assert(fruits.length == 5);

// Remove a single item.
var appleIndex = fruits.indexOf('apples');
fruits.removeAt(appleIndex);
assert(fruits.length == 4);

// Remove all elements from a list.
fruits.clear();
assert(fruits.isEmpty);

// You can also create a List using one of the constructors.
var vegetables = List.filled(99, 'broccoli');
assert(vegetables.every((v) => v == 'broccoli'));

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

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

// Access a list item by index.
assert(fruits[0] == 'apples');

// Find an item in a list.
assert(fruits.indexOf('apples') == 0);

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

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

// Sort a list.
fruits.sort((a, b) => a.compareTo(b));
assert(fruits[0] == 'apples');

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

dart
// This list should contain only strings.
var fruits = <String>[];

fruits.add('apples');
var fruit = fruits[0];
assert(fruit is String);
✗ 静态分析:失败dart
fruits.add(5); // Error: 'int' can't be assigned to 'String'

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

集合

#

Dart 中的集合是唯一项目的无序集合。由于集合是无序的,因此你无法按索引(位置)获取集合的项目。

dart
// Create an empty set of strings.
var ingredients = <String>{};

// Add new items to it.
ingredients.addAll(['gold', 'titanium', 'xenon']);
assert(ingredients.length == 3);

// Adding a duplicate item has no effect.
ingredients.add('gold');
assert(ingredients.length == 3);

// Remove an item from a set.
ingredients.remove('gold');
assert(ingredients.length == 2);

// You can also create sets using
// one of the constructors.
var atomicNumbers = Set.from([79, 22, 54]);

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

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

// Check whether an item is in the set.
assert(ingredients.contains('titanium'));

// Check whether all the items are in the set.
assert(ingredients.containsAll(['titanium', 'xenon']));

交集是一个集合,其项目存在于另外两个集合中。

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

// Create the intersection of two sets.
var nobleGases = Set.from(['xenon', 'argon']);
var intersection = ingredients.intersection(nobleGases);
assert(intersection.length == 1);
assert(intersection.contains('xenon'));

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

映射

#

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

你可以使用简洁的字面量语法来声明映射,或者可以使用传统的构造函数

dart
// Maps often use strings as keys.
var hawaiianBeaches = {
  'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  'Big Island': ['Wailea Bay', 'Pololu Beach'],
  'Kauai': ['Hanalei', 'Poipu']
};

// Maps can be built from a constructor.
var searchTerms = Map();

// Maps are parameterized types; you can specify what
// types the key and value should be.
var nobleGases = Map<int, String>();

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

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

// Retrieve a value with a key.
assert(nobleGases[54] == 'xenon');

// Check whether a map contains a key.
assert(nobleGases.containsKey(54));

// Remove a key and its value.
nobleGases.remove(54);
assert(!nobleGases.containsKey(54));

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

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

// Get all the keys as an unordered collection
// (an Iterable).
var keys = hawaiianBeaches.keys;

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

// Get all the values as an unordered collection
// (an Iterable of Lists).
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 共享许多集合中常见的函数。其中一些通用函数由 Iterable 类定义,List 和 Set 实现该类。

使用 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('I drink $tea'));

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

dart
hawaiianBeaches.forEach((k, v) {
  print('I want to visit $k and swim at $v');
  // I want to visit Oahu and swim at
  // [Waikiki, Kailua, Waimanalo], etc.
});

Iterables 提供 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'];

// Chamomile is not caffeinated.
bool isDecaffeinated(String teaName) => teaName == 'chamomile';

// Use where() to find only the items that return true
// from the provided function.
var decaffeinatedTeas = teas.where((tea) => isDecaffeinated(tea));
// or teas.where(isDecaffeinated)

// Use any() to check whether at least one item in the
// collection satisfies a condition.
assert(teas.any(isDecaffeinated));

// Use every() to check whether all the items in a
// collection satisfy a condition.
assert(!teas.every(isDecaffeinated));

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

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 组件,请参阅 Uri API 参考

构建 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
// Get the current date and time.
var now = DateTime.now();

// Create a new DateTime with the local time zone.
var y2k = DateTime(2000); // January 1, 2000

// Specify the month and day.
y2k = DateTime(2000, 1, 2); // January 2, 2000

// Specify the date as a UTC time.
y2k = DateTime.utc(2000); // 1/1/2000, UTC

// Specify a date and time in ms since the Unix epoch.
y2k = DateTime.fromMillisecondsSinceEpoch(946684800000, isUtc: true);

// Parse an ISO 8601 date in the UTC time zone.
y2k = DateTime.parse('2000-01-01T00:00:00Z');

// Create a new DateTime from an existing one, adjusting just some properties:
var sameTimeLastYear = now.copyWith(year: now.year - 1);

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

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

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

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

dart
var y2k = DateTime.utc(2000);

// Add one year.
var y2001 = y2k.add(const Duration(days: 366));
assert(y2001.year == 2001);

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

// Calculate the difference between two dates.
// Returns a Duration object.
var duration = y2001.difference(y2k);
assert(duration.inDays == 366); // y2k was a leap year.

有关方法的完整列表,请参阅 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 获取器以生成自定义哈希码。如果您这样做,您可能还想覆盖 == 运算符。相等的(通过 ==)对象必须具有相同的哈希码。哈希码不必是唯一的,但它应该是均匀分布的。

dart
class Person {
  final String firstName, lastName;

  Person(this.firstName, this.lastName);

  // Override hashCode using the static hashing methods
  // provided by the `Object` class.
  @override
  int get hashCode => Object.hash(firstName, lastName);

  // You should generally implement operator `==` if you
  // override `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 {
  // Represents a process...
}

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

// A mythical class that lets you iterate through all
// processes. Extends a subclass of [Iterable].
class Processes extends IterableBase<Process> {
  @override
  final Iterator<Process> iterator = ProcessIterator();
}

void main() {
  // Iterable objects can be used with for-in.
  for (final process in Processes()) {
    // Do something with the process.
  }
}

异常

#

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 时,它不会被垃圾回收,直到声明它的代码块退出。