dart:core
dart:core 库(API 参考)提供了一组小的但至关重要的内置功能。此库会自动导入到每个 Dart 程序中。
打印到控制台
#顶层 print()
方法接受一个参数(任何对象),并在控制台中显示该对象的字符串值(由 toString()
返回)。
print(anObject);
print('I drink $tea.');
有关基本字符串和 toString()
的更多信息,请参见语言游览中的字符串。
数字
#dart:core 库定义了 num、int 和 double 类,它们有一些用于处理数字的基本实用程序。
你可以分别使用 int 和 double 的 parse()
方法将字符串转换为整数或双精度数
assert(int.parse('42') == 42);
assert(int.parse('0x42') == 66);
assert(double.parse('0.50') == 0.5);
或者使用 num 的 parse() 方法,如果可能,它将创建一个整数,否则将创建一个双精度数
assert(num.parse('42') is int);
assert(num.parse('0x42') is int);
assert(num.parse('0.50') is double);
要指定整数的基数,请添加一个 radix
参数
assert(int.parse('42', radix: 16) == 66);
使用 toString()
方法将 int 或 double 转换为字符串。要指定小数点右边的位数,请使用 toStringAsFixed(). 要指定字符串中的有效位数,请使用 toStringAsPrecision():
// 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()
等方法。
在字符串中搜索
#你可以查找字符串中的特定位置,以及检查字符串是否以特定模式开头或结尾。例如
// 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}'))包含两个代码单元。
你还可以提取子字符串或将字符串拆分为子字符串列表
// 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
包。::
转换为大写或小写
#你可以轻松地将字符串转换为其大写和小写变体
// Convert to uppercase.
assert('web apps'.toUpperCase() == 'WEB APPS');
// Convert to lowercase.
assert('WEB APPS'.toLowerCase() == 'web apps');
修剪和空字符串
#使用 trim()
删除所有前导和尾随空格。要检查字符串是否为空(长度为零),请使用 isEmpty
。
// 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
var greetingTemplate = 'Hello, NAME!';
var greeting = greetingTemplate.replaceAll(RegExp('NAME'), 'Bob');
// greetingTemplate didn't change.
assert(greeting != greetingTemplate);
构建字符串
#要以编程方式生成字符串,可以使用 StringBuffer。在调用 toString()
之前,StringBuffer 不会生成新的 String 对象。writeAll()
方法有一个可选的第二个参数,可让你指定分隔符(在本例中为空格)。
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 正则表达式相同的功能。使用正则表达式高效地搜索和匹配字符串模式。
// 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 类提供对正则表达式匹配的访问权限。
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 类还定义了一些方法,用于向列表添加项目和从列表中删除项目。
// 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()
查找列表中对象的索引
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 实现。
var fruits = ['bananas', 'apples', 'oranges'];
// Sort a list.
fruits.sort((a, b) => a.compareTo(b));
assert(fruits[0] == 'apples');
列表是参数化类型(泛型),因此你可以指定列表应包含的类型
// This list should contain only strings.
var fruits = <String>[];
fruits.add('apples');
var fruit = fruits[0];
assert(fruit is String);
fruits.add(5); // Error: 'int' can't be assigned to 'String'
有关方法的完整列表,请参阅 List API 参考。
集合
#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()
检查一个或多个对象是否在集合中
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']));
交集是一个集合,其项目存在于另外两个集合中。
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 对象不是映射。
你可以使用简洁的字面量语法来声明映射,或者可以使用传统的构造函数
// 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()
从映射中删除键及其值。
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));
你可以从映射中检索所有值或所有键
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 来确定键是否存在。
var hawaiianBeaches = {
'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
'Big Island': ['Wailea Bay', 'Pololu Beach'],
'Kauai': ['Hanalei', 'Poipu']
};
assert(hawaiianBeaches.containsKey('Oahu'));
assert(!hawaiianBeaches.containsKey('Florida'));
当您想要仅当键在映射中不存在时才为键分配值时,请使用 putIfAbsent()
方法。您必须提供一个返回值的函数。
var teamAssignments = <String, String>{};
teamAssignments.putIfAbsent('Catcher', () => pickToughestKid());
assert(teamAssignments['Catcher'] != null);
有关方法的完整列表,请参阅 Map API 参考。
常见集合方法
#List、Set 和 Map 共享许多集合中常见的函数。其中一些通用函数由 Iterable 类定义,List 和 Set 实现该类。
使用 isEmpty
或 isNotEmpty
检查列表、集合或映射中是否包含项目。
var coffees = <String>[];
var teas = ['green', 'black', 'chamomile', 'earl grey'];
assert(coffees.isEmpty);
assert(teas.isNotEmpty);
要将函数应用于列表、集合或映射中的每个项目,可以使用 forEach()
。
var teas = ['green', 'black', 'chamomile', 'earl grey'];
teas.forEach((tea) => print('I drink $tea'));
当您在映射上调用 forEach()
时,您的函数必须接受两个参数(键和值)。
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()
方法,该方法提供单个对象中的所有结果。
var teas = ['green', 'black', 'chamomile', 'earl grey'];
var loudTeas = teas.map((tea) => tea.toUpperCase());
loudTeas.forEach(print);
要强制您的函数立即在每个项目上调用,请使用 map().toList()
或 map().toSet()
。
var loudTeas = teas.map((tea) => tea.toUpperCase()).toList();
使用 Iterable 的 where()
方法获取满足条件的所有项目。使用 Iterable 的 any()
和 every()
方法检查是否有某些或所有项目满足条件。
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 参考,以及 List、Set 和 Map 的参考。
URI
#Uri 类 提供函数来对字符串进行编码和解码,以便在 URI(您可能将其称为 URL)中使用。这些函数处理对 URI 具有特殊意义的字符,例如 &
和 =
。Uri 类还会解析并公开 URI 的组件——主机、端口、方案等。
编码和解码完全限定 URI
#要对 除了 在 URI 中具有特殊意义的字符(例如 /
、:
、&
、#
)之外的所有字符进行编码和解码,请使用 encodeFull()
和 decodeFull()
方法。这些方法适合对完全限定的 URI 进行编码或解码,并保留完整的特殊 URI 字符。
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);
注意,只有 some
和 message
之间的空格被编码了。
编码和解码 URI 组件
#要对字符串中所有在 URI 中具有特殊意义的字符(包括但不限于 /
、&
和 :
)进行编码和解码,请使用 encodeComponent()
和 decodeComponent()
方法。
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()
静态方法。
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。
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.http
或 Uri.https
工厂构造函数。
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 对象。
// 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)以来的毫秒数。
// 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 类计算两个日期之间的差值,以及将日期向前或向后移动。
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.
有关方法的完整列表,请参阅 DateTime 和 Duration 的 API 参考。
实用程序类
#核心库包含各种实用程序类,可用于排序、映射值和迭代。
比较对象
#实现 Comparable 接口以指示对象可以与另一个对象进行比较,通常用于排序。compareTo()
方法返回 < 0 表示 更小,0 表示 相同,> 0 表示 更大。
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
获取器以生成自定义哈希码。如果您这样做,您可能还想覆盖 ==
运算符。相等的(通过 ==
)对象必须具有相同的哈希码。哈希码不必是唯一的,但它应该是均匀分布的。
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);
}
迭代
#Iterable 和 Iterator 类支持对值集合进行顺序访问。要练习使用这些集合,请遵循 Iterable 集合教程。
如果您创建了一个可以为 for-in 循环提供迭代器的类,请扩展(如果可能)或实现 Iterable。实现 Iterator 以定义实际的迭代能力。
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 接口来定义自定义异常。
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 时,它不会被垃圾回收,直到声明它的代码块退出。
除非另有说明,否则此网站上的文档反映了 Dart 3.5.3。页面最后更新于 2024-06-10。 查看源代码 或 报告问题.