目录

dart:core

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

打印到控制台

#

顶层 print() 方法接受一个参数(任何 Object),并在控制台中显示该对象的字符串值(由 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() 方法将整数或双精度浮点数转换为字符串。要指定小数点右侧的位数,请使用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);

从字符串中提取数据

#

您可以分别以字符串或整数形式获取字符串中的单个字符。准确地说,您实际上获取的是单个 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 参考

映射

#

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

你可以使用简洁的字面量语法声明 Map,也可以使用传统的构造函数

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

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

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

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

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

要检查 Map 是否包含键,请使用 containsKey()。 因为 Map 值可以为 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'));

当你只想在 Map 中不存在键时才为键赋值时,请使用 putIfAbsent() 方法。 你必须提供一个返回值的函数。

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

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

常用集合方法

#

List、Set 和 Map 共享许多集合中的常见功能。 这些常见功能中的一些是由 Iterable 类定义的,List 和 Set 实现了该类。

使用 isEmptyisNotEmpty 来检查列表、集合或 Map 是否有项

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

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

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

teas.forEach((tea) => print('I drink $tea'));

当你在 Map 上调用 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.
});

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'];

// 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 中的每个对象都会自动提供一个整数哈希码,因此可以用作 Map 中的键。 但是,你可以重写 hashCode getter 以生成自定义哈希码。 如果这样做,你可能还需要重写 == 运算符。 相等(通过 ==)的对象必须具有相同的哈希码。 哈希码不必是唯一的,但它应该分布均匀。

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