目录

Contents

Dart 语言核心库一览

本页介绍如何使用 Dart 核心库中的主要功能。这只是一个概览,并不全面。当你需要有关类的更多详细信息时,请参阅Dart API 参考

This page shows you how to use the major features in Dart’s core libraries. It’s just an overview, and by no means comprehensive. Whenever you need more details about a class, consult the Dart API reference.

dart:core
Built-in types, collections, and other core functionality. This library is automatically imported into every Dart program.

内置类型,集合和其他核心功能。该库会被自动导入到所有的 Dart 程序。

dart:async
Support for asynchronous programming, with classes such as Future and Stream.

支持异步编程,包括Future和Stream等类。

dart:math
Mathematical constants and functions, plus a random number generator.

数学常数和函数,以及随机数生成器。

dart:convert
Encoders and decoders for converting between different data representations, including JSON and UTF-8.

用于在不同数据表示之间进行转换的编码器和解码器,包括 JSON 和 UTF-8。

dart:html
DOM and other APIs for browser-based apps.

用于基于浏览器应用的 DOM 和其他 API。

dart:io
I/O for programs that can use the Dart VM, including Flutter apps, servers, and command-line scripts.

服务器和命令行应用程序的 I/O 操作,包括 Flutter 应用,服务端应用,以及命令行脚本。

本章只是一个概述;只涵盖了几个 dart:* 库,不包括第三方库。

This page is just an overview; it covers only a few dart:* libraries and no third-party libraries.

更多库信息可以在 [Pub site][pub.dartlang] 和 Dart web developer library guide. 查找。所有 dart:* 库的 API 文档可以在 Dart API reference 查找,如果使用的是 Flutter 可以在 Flutter API reference. 查找。

Other places to find library information are the pub.dev site and the Dart web developer library guide. You can find API documentation for all dart:* libraries in the Dart API reference or, if you’re using Flutter, the Flutter API reference.

dart:core - 数字,集合,字符串等

dart:core - numbers, collections, strings, and more

dart:core 库 (API reference) 提供了一个少量但是重要的内置功能集合。该库会被自动导入每个 Dart 程序。

The dart:core library (API reference) provides a small but critical set of built-in functionality. This library is automatically imported into every Dart program.

控制台打印

Printing to the console

顶级 print() 方法接受一个参数任意对象)并输出显示这个对象的字符串值(由 toString() 返回) 到控制台。

The top-level print() method takes a single argument (any Object) and displays that object’s string value (as returned by toString()) in the console.

print(anObject);
print('I drink $tea.');

有关基本字符串和 toString() 的更多信息,参考 Strings in the language tour.

For more information on basic strings and toString(), see Strings in the language tour.

数字

Numbers

dart:core 库定义了 num ,int 以及 double 类,这些类拥有一定的工具方法来处理数字。

The dart:core library defines the num, int, and double classes, which have some basic utilities for working with numbers.

使用 int 和 double 的 parse() 方法将字符串转换为整型或双浮点型对象:

You can convert a string into an integer or double with the parse() methods of int and double, respectively:

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

或者使用 num 的 parse() 方法,该方法可能会创建一个整型,否则为浮点型对象:

Or use the parse() method of num, which creates an integer if possible and otherwise a double:

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

通过添加 radix 参数,指定整数的进制基数:

To specify the base of an integer, add a radix parameter:

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

使用 toString() 方法将整型或双精度浮点类型转换为字符串类型。使用 toStringAsFixed(). 指定小数点右边的位数,使用 toStringAsPrecision(): 指定字符串中的有效数字的位数。

Use the toString() method to convert an int or double to a string. To specify the number of digits to the right of the decimal, use toStringAsFixed(). To specify the number of significant digits in the string, use 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);

For more information, see the API documentation for int, double, and num. Also see the dart:math section.

字符和正则表达式

Strings and regular expressions

在 Dart 中一个字符串是一个固定不变的 UTF-16 编码单元序列。语言概览中有更多关于 strings 的内容。使用正则表达式 (RegExp 对象) 可以在字符串内搜索和替换部分字符串。

A string in Dart is an immutable sequence of UTF-16 code units. The language tour has more information about strings. You can use regular expressions (RegExp objects) to search within strings and to replace parts of strings.

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

The String class defines such methods as split(), contains(), startsWith(), endsWith(), and more.

在字符串中搜索

Searching inside a string

可以在字符串内查找特定字符串的位置,以及检查字符串是否以特定字符串作为开头或结尾。例如:

You can find particular locations within a string, as well as check whether a string begins with or ends with a particular pattern. For example:

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

从字符串中提取数据

Extracting data from a string

可以获取字符串中的单个字符,将其作为字符串或者整数。确切地说,实际上获取的是单独的UTF-16编码单元; 诸如高音谱号符号 (‘\u{1D11E}’) 之类的高编号字符分别为两个编码单元。

You can get the individual characters from a string as Strings or ints, respectively. To be precise, you actually get individual UTF-16 code units; high-numbered characters such as the treble clef symbol (‘\u{1D11E}’) are two code units apiece.

你也可以获取字符串中的子字符串或者将一个字符串分割为子字符串列表:

You can also extract a substring or split a string into a list of substrings:

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

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

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

首字母大小写转换

Converting to uppercase or lowercase

可以轻松的对字符串的首字母大小写进行转换:

You can easily convert strings to their uppercase and lowercase variants:

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

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

提示: 这些方法不是在所有语言上都有效的。例如,土耳其字母表的无点 I 转换是不正确的。

Note: These methods don’t work for every language. For example, the Turkish alphabet’s dotless I is converted incorrectly.

Trimming 和空字符串

Trimming and empty strings

使用 trim() 移除首尾空格。使用 isEmpty 检查一个字符串是否为空(长度为0)。

Remove all leading and trailing white space with trim(). To check whether a string is empty (length is zero), use 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);

替换部分字符串

Replacing part of a string

字符串是不可变的对象,也就是说字符串可以创建但是不能被修改。如果仔细阅读了 String API docs, 你会注意到,没有一个方法实际的改变了字符串的状态。例如,方法 replaceAll() 返回一个新字符串,并没有改变原始字符串:

Strings are immutable objects, which means you can create them but you can’t change them. If you look closely at the String API reference, you’ll notice that none of the methods actually changes the state of a String. For example, the method replaceAll() returns a new String without changing the original String:

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

// greetingTemplate didn't change.
assert(greeting != greetingTemplate);

构建一个字符串

Building a string

要以代码方式生成字符串,可以使用 StringBuffer 。在调用 toString() 之前, StringBuffer 不会生成新字符串对象。 writeAll() 的第二个参数为可选参数,用来指定分隔符,本例中使用空格作为分隔符。

To programmatically generate a string, you can use StringBuffer. A StringBuffer doesn’t generate a new String object until toString() is called. The writeAll() method has an optional second parameter that lets you specify a separator—in this case, a space.

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

正则表达式

Regular expressions

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

The RegExp class provides the same capabilities as JavaScript regular expressions. Use regular expressions for efficient searching and pattern matching of strings.

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

You can work directly with the RegExp class, too. The Match class provides access to a regular expression 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 (var match in numbers.allMatches(someDigits)) {
  print(match.group(0)); // 15, then 20
}

更多信息

More information

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

Refer to the String API reference for a full list of methods. Also see the API reference for StringBuffer, Pattern, RegExp, and Match.

集合

Collections

Dart 附带了核心集合 API ,其中包括 list ,set 和 map 类。

Dart ships with a core collections API, which includes classes for lists, sets, and maps.

Lists

如语言概览中介绍,lists 可以通过字面量来创建和初始化。另外,也可以使用 List 的构造函数。 List 类还定义了若干方法,用于向列表添加或删除项目。

As the language tour shows, you can use literals to create and initialize lists. Alternatively, use one of the List constructors. The List class also defines several methods for adding items to and removing items from lists.

// Use a List constructor.
var vegetables = List();

// Or simply use 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);

使用 indexOf() 方法查找一个对象在 list 中的下标值。

Use indexOf() to find the index of an object in a list:

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() 方法排序一个 list 。你可以提供一个排序函数用于比较两个对象。比较函数在 小于 时返回 \ <0,相等 时返回 0,bigger 时返回 > 0 。下面示例中使用 compareTo() 函数,该函数在 Comparable 中定义,并被 String 类实现。

Sort a list using the sort() method. You can provide a sorting function that compares two objects. This sorting function must return < 0 for smaller, 0 for the same, and > 0 for bigger. The following example uses compareTo(), which is defined by Comparable and implemented by String.

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

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

list 是参数化类型,因此可以指定 list 应该包含的元素类型:

Lists are parameterized types, so you can specify the type that a list should contain:

// This list should contain only strings.
var fruits = List<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 docs

Refer to the List API reference for a full list of methods.

Sets

在 Dart 中,set 是一个无序的,元素唯一的集合。因为一个 set 是无序的,所以无法通过下标(位置)获取 set 中的元素。

A set in Dart is an unordered collection of unique items. Because a set is unordered, you can’t get a set’s items by index (position).

var ingredients = Set();
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);

使用 contains()containsAll() 来检查一个或多个元素是否在 set 中:

Use contains() and containsAll() to check whether one or more objects are in a set:

var ingredients = Set();
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']));

交集是另外两个 set 中的公共元素组成的 set。

An intersection is a set whose items are in two other sets.

var ingredients = Set();
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 docs

Refer to the Set API reference for a full list of methods.

Maps

map 是一个无序的 key-value (键值对)集合,就是大家熟知的 dictionary 或者 hash。 map 将 kay 与 value 关联,以便于检索。和 JavaScript 不同,Dart 对象不是 map。

A map, commonly known as a dictionary or hash, is an unordered collection of key-value pairs. Maps associate a key to some value for easy retrieval. Unlike in JavaScript, Dart objects are not maps.

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

You can declare a map using a terse literal syntax, or you can use a traditional constructor:

// 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 中移除键值对。

You add, get, and set map items using the bracket syntax. Use remove() to remove a key and its value from a map.

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 中检索出所有的 key 或所有的 value:

You can retrieve all the values or all the keys from a map:

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() 方法检查一个 map 中是否包含某个key 。因为 map 中的 value 可能会是 null ,所有通过 key 获取 value,并通过判断 value 是否为 null 来判断 key 是否存在是不可靠的。

To check whether a map contains a key, use containsKey(). Because map values can be null, you cannot rely on simply getting the value for the key and checking for null to determine the existence of a key.

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

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

如果当且仅当该 key 不存在于 map 中,且要为这个 key 赋值,可使用putIfAbsent()方法。该方法需要一个方法返回这个 value。

Use the putIfAbsent() method when you want to assign a value to a key if and only if the key does not already exist in a map. You must provide a function that returns the value.

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

全部的方法介绍,请参考 Map API docs

Refer to the Map API reference for a full list of methods.

公共集合方法

Common collection methods

List, Set, 和 Map 共享许多集合中的常用功能。其中一些常见功能由 Iterable 类定义,这些函数由 List 和 Set 实现。

List, Set, and Map share common functionality found in many collections. Some of this common functionality is defined by the Iterable class, which List and Set implement.

提示:

Note:

虽然Map没有实现 Iterable,但可以使用 Map keysvalues 属性从中获取 Iterable 对象。

Although Map doesn’t implement Iterable, you can get Iterables from it using the Map keys and values properties.

使用 isEmptyisNotEmpty 方法可以检查 list, set 或 map 对象中是否包含元素:

Use isEmpty or isNotEmpty to check whether a list, set, or map has items:

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

使用 forEach() 可以让 list, set 或 map 对象中的每个元素都使用一个方法。

To apply a function to each item in a list, set, or map, you can use forEach():

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

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

当在 map 对象上调用 `forEach() 方法时,函数必须带两个参数(key 和 value):

When you invoke forEach() on a map, your function must take two arguments (the key and value):

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() 方法,这个方法将所有结果返回到一个对象中。

Iterables provide the map() method, which gives you all the results in a single object:

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

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

提示:

Note:

map() 方法返回的对象是一个 懒求值(lazily evaluated)对象:只有当访问对象里面的元素时,函数才会被调用。

The object returned by map() is an Iterable that’s lazily evaluated: your function isn’t called until you ask for an item from the returned object.

使用 map().toList()map().toSet() ,可以强制在每个项目上立即调用函数。

To force your function to be called immediately on each item, use map().toList() or map().toSet():

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

使用 Iterable 的 where() 方法可以获取所有匹配条件的元素。使用 Iterable 的 any()every() 方法可以检查部分或者所有元素是否匹配某个条件。

Use Iterable’s where() method to get all the items that match a condition. Use Iterable’s any() and every() methods to check whether some or all items match a condition.

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 docs, 以及 List, Set, and Map.

For a full list of methods, refer to the Iterable API reference, as well as those for List, Set, and Map.

URIs

在使用 URI(可能你会称它为 URLs)时,Uri 类 提供对字符串的编解码操作。这些函数用来处理 URI 特有的字符,例如 = 。 Uri 类还可以解析和处理 URI—host,port,scheme等组件。

The Uri class provides functions to encode and decode strings for use in URIs (which you might know as URLs). These functions handle characters that are special for URIs, such as & and =. The Uri class also parses and exposes the components of a URI—host, port, scheme, and so on.

编码和解码完整合法的URI

Encoding and decoding fully qualified URIs

使用 encodeFull()decodeFull() 方法,对 URI 中除了特殊字符(例如 /:&#)以外的字符进行编解码,这些方法非常适合编解码完整合法的 URI,并保留 URI 中的特殊字符。

To encode and decode characters except those with special meaning in a URI (such as /, :, &, #), use the encodeFull() and decodeFull() methods. These methods are good for encoding or decoding a fully qualified URI, leaving intact special URI characters.

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

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

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

注意上面代码只编码了 somemessage 之间的空格。

Notice how only the space between some and message was encoded.

编码和解码 URI 组件

Encoding and decoding URI components

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

To encode and decode all of a string’s characters that have special meaning in a URI, including (but not limited to) /, &, and :, use the encodeComponent() and decodeComponent() methods.

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

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

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

注意上面代码编码了所有的字符。例如 / 被编码为 %2F

Notice how every special character is encoded. For example, / is encoded to %2F.

解析 URI

Parsing URIs

使用 Uri 对象的字段(例如 path),来获取一个 Uri 对象或者 URI 字符串的一部分。使用 parse() 静态方法,可以使用字符串创建 Uri 对象。

If you have a Uri object or a URI string, you can get its parts using Uri fields such as path. To create a Uri from a string, use the parse() static method:

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

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

有关 URI 组件的更多内容,参考 Uri API docs

See the Uri API reference for more URI components that you can get.

构建 URI

Building URIs

使用 Uri() 构造函数,可以将各组件部分构建成 URI 。

You can build up a URI from individual parts using the Uri() constructor:

var uri = Uri(
    scheme: 'http',
    host: 'example.org',
    path: '/foo/bar',
    fragment: 'frag');
assert(
    uri.toString() == 'http://example.org/foo/bar#frag');

日期和时间

Dates and times

DateTime 对象代表某个时刻,时区可以是 UTC 或者本地时区。

A DateTime object is a point in time. The time zone is either UTC or the local time zone.

DateTime 对象可以通过若干构造函数创建:

You can create DateTime objects using several constructors:

// 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.
y2k = DateTime.parse('2000-01-01T00:00:00Z');

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

The millisecondsSinceEpoch property of a date returns the number of milliseconds since the “Unix epoch”—January 1, 1970, 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);

Use the Duration class to calculate the difference between two dates and to shift a date forward or backward:

var y2k = DateTime.utc(2000);

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

// Subtract 30 days.
var december2000 = y2001.subtract(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.

警告:

Warning:

由于时钟转换(例如,夏令时)的原因,使用 Duration 对 DateTime 按天移动可能会有问题。如果要按照天数来位移时间,请使用 UTC 日期。

Using a Duration to shift a DateTime by days can be problematic, due to clock shifts (to daylight saving time, for example). Use UTC dates if you must shift days.

参考 DateTimeDuration API 文档了解全部方法列表。

For a full list of methods, refer to the API reference for DateTime and Duration.

工具类

Utility classes

核心库包含各种工具类,可用于排序,映射值以及迭代。

The core library contains various utility classes, useful for sorting, mapping values, and iterating.

比较对象

Comparing objects

如果实现了 Comparable 接口,也就是说可以将该对象与另一个对象进行比较,通常用于排序。 compareTo() 方法在 小于 时返回 < 0,在 相等 时返回 0,在 大于 时返回 > 0。

Implement the Comparable interface to indicate that an object can be compared to another object, usually for sorting. The compareTo() method returns < 0 for smaller, 0 for the same, and > 0 for bigger.

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

Implementing map keys

在 Dart 中每个对象会默认提供一个整数的哈希值,因此在 map 中可以作为 key 来使用,重写 hashCode 的 getter 方法来生成自定义哈希值。如果重写 hashCode 的 getter 方法,那么可能还需要重写 == 运算符。相等的(通过 == )对象必须拥有相同的哈希值。哈希值并不要求是唯一的,但是应该具有良好的分布形态。

Each object in Dart automatically provides an integer hash code, and thus can be used as a key in a map. However, you can override the hashCode getter to generate a custom hash code. If you do, you might also want to override the == operator. Objects that are equal (via ==) must have identical hash codes. A hash code doesn’t have to be unique, but it should be well distributed.

class Person {
  final String firstName, lastName;

  Person(this.firstName, this.lastName);

  // Override hashCode using strategy from Effective Java,
  // Chapter 11.
  @override
  int get hashCode {
    int result = 17;
    result = 37 * result + firstName.hashCode;
    result = 37 * result + lastName.hashCode;
    return result;
  }

  // You should generally implement operator == if you
  // override hashCode.
  @override
  bool operator ==(dynamic other) {
    if (other is! Person) return false;
    Person person = other;
    return (person.firstName == firstName &&
        person.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);
}

迭代

Iteration

IterableIterator 类支持 for-in 循环。当创建一个类的时候,继承或者实现 Iterable,可以为该类提供用于 for-in 循环的 Iterators。实现 Iterator 来定义实际的遍历操作。

The Iterable and Iterator classes support for-in loops. Extend (if possible) or implement Iterable whenever you create a class that can provide Iterators for use in for-in loops. Implement Iterator to define the actual iteration ability.

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 (var process in Processes()) {
    // Do something with the process.
  }
}

异常

Exceptions

Dart 核心库定义了很多公共的异常和错误类。异常通常是一些可以预见和预知的情况。错误是无法预见或者预防的情况。

The Dart core library defines many common exceptions and errors. Exceptions are considered conditions that you can plan ahead for and catch. Errors are conditions that you don’t expect or plan for.

两个最常见的错误:

A couple of the most common errors are:

NoSuchMethodError

当方法的接受对象(可能为null)没有实现该方法时抛出。

Thrown when a receiving object (which might be null) does not implement a method.

ArgumentError

当方法在接受到一个不合法参数时抛出。

Can be thrown by a method that encounters an unexpected argument.

通常通过抛出一个应用特定的异常,来表示应用发生了错误。通过实现 Exception 接口来自定义异常:

Throwing an application-specific exception is a common way to indicate that an error has occurred. You can define a custom exception by implementing the Exception interface:

class FooException implements Exception {
  final String msg;

  const FooException([this.msg]);

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

更多内容,参考 Exceptions 以及 Exception API 文档。

For more information, see Exceptions (in the language tour) and the Exception API reference.

dart:async - 异步编程

dart:async - asynchronous programming

异步编程通常使用回调方法来实现,但是 Dart 提供了其他方案:FutureStream 对象。 Future 类似与 JavaScript 中的 Promise ,代表在将来某个时刻会返回一个结果。 Stream 类可以用来获取一系列的值,比如,一些列事件。 Future, Stream,以及更多内容,参考 dart:async library (API reference)。

Asynchronous programming often uses callback functions, but Dart provides alternatives: Future and Stream objects. A Future is like a promise for a result to be provided sometime in the future. A Stream is a way to get a sequence of values, such as events. Future, Stream, and more are in the dart:async library (API reference).

提示:

Note:

你并不总是需要直接使用 Future 或 Stream 的 API。 Dart 语言支持使用关键字(例如,asyncawait )来实现异步编程。更多详情,参考这个 codelab 了解更多:asynchronous programming codelab

You don’t always need to use the Future or Stream APIs directly. The Dart language supports asynchronous coding using keywords such as async and await. See the asynchronous programming codelab for details.

dart:async 库可以工作在 web 应用及 command-line 应用。通过 import dart:async 来使用。

The dart:async library works in both web apps and command-line apps. To use it, import dart:async:

import 'dart:async';

Future

在 Dart 库中随处可见 Future 对象,通常异步函数返回的对象就是一个 Future。当一个 future 完成执行后,future 中的值就已经可以使用了。

Future objects appear throughout the Dart libraries, often as the object returned by an asynchronous method. When a future completes, its value is ready to use.

使用 await

Using await

在直接使用 Future API 前,首先应该考虑 await 来替代。代码中使用 await 表达式会比直接使用 Future API 更容易理解。

Before you directly use the Future API, consider using await instead. Code that uses await expressions can be easier to understand than code that uses the Future API.

阅读思考下面代码。代码使用 Future 的 then() 方法在同一行执行了三个异步函数,要等待上一个执行完成,再执行下一个任务。

Consider the following function. It uses Future’s then() method to execute three asynchronous functions in a row, waiting for each one to complete before executing the next one.

runUsingFuture() {
  // ...
  findEntryPoint().then((entryPoint) {
    return runExecutable(entryPoint, args);
  }).then(flushThenExit);
}

通过 await 表达式实现等价的代码,看起来非常像同步代码:

The equivalent code with await expressions looks more like synchronous code:

runUsingAsyncAwait() async {
  // ...
  var entryPoint = await findEntryPoint();
  var exitCode = await runExecutable(entryPoint, args);
  await flushThenExit(exitCode);
}

async 函数能够捕获来自 Future 的异常。例如:

An async function can catch exceptions from Futures. For example:

var entryPoint = await findEntryPoint();
try {
  var exitCode = await runExecutable(entryPoint, args);
  await flushThenExit(exitCode);
} catch (e) {
  // Handle the error...
}

重要:

Important:

async 函数返回 Future 对象。如果你不希望你的函数返回一个 future 对象,可以使用其他方案。例如,你可以在你的方法中调用一个 async 方法。

Async functions return Futures. If you don’t want your function to return a future, then use a different solution. For example, you might call an async function from your function.

更多关于 await 的使用及相关的 Dart 语言特征,参考 Asynchrony support

For more information on using await and related Dart language features, see the asynchronous programming codelab.

基本用法

Basic usage

当 future 执行完成后,then() 中的代码会被执行。then() 中的代码会在 future 完成后被执行。例如,HttpRequest.getString() 返回一个 future 对象,因为 HTTP 请求可能需要一段时间。当 Future 完成并且保证字符串值有效后,使用 then() 来执行你需要的代码:

You can use then() to schedule code that runs when the future completes. For example, HttpRequest.getString() returns a Future, since HTTP requests can take a while. Using then() lets you run some code when that Future has completed and the promised string value is available:

HttpRequest.getString(url).then((String result) {
  print(result);
});

使用 catchError() 来处理一些 Future 对象可能抛出的错误或者异常。

Use catchError() to handle any errors or exceptions that a Future object might throw.

HttpRequest.getString(url).then((String result) {
  print(result);
}).catchError((e) {
  // Handle or ignore the error.
});

then().catchError() 组合是 try-catch 的异步版本。

The then().catchError() pattern is the asynchronous version of try-catch.

重要:

Important:

确保调用 catchError() 方式在 then() 的结果上,而不是在原来的 Future 对象上调用。否则的话,catchError() 就只能处理原来 Future 对象抛出的异常,而无法处理 then() 代码里面的异常。

Be sure to invoke catchError() on the result of then()—not on the result of the original Future. Otherwise, the catchError() can handle errors only from the original Future’s computation, but not from the handler registered by then().

链式异步编程

Chaining multiple asynchronous methods

then() 方法返回一个 Future 对象,这样就提供了一个非常好的方式让多个异步方法按顺序依次执行。如果用 then() 注册的回调返回一个 Future ,那么 then() 返回一个等价的 Future 。如果回调返回任何其他类型的值,那么 then() 会创建一个以该值完成的新 Future 。

The then() method returns a Future, providing a useful way to run multiple asynchronous functions in a certain order. If the callback registered with then() returns a Future, then() returns an equivalent Future. If the callback returns a value of any other type, then() creates a new Future that completes with the value.

Future result = costlyQuery(url);
result
    .then((value) => expensiveWork(value))
    .then((_) => lengthyComputation())
    .then((_) => print('Done!'))
    .catchError((exception) {
  /* Handle exception... */
});

在上面的示例中,方法按下面顺序执行:

In the preceding example, the methods run in the following order:

  1. costlyQuery()
  2. expensiveWork()
  3. lengthyComputation()

这是使用 await 编写的等效代码:

Here is the same code written using await:

try {
  final value = await costlyQuery(url);
  await expensiveWork(value);
  await lengthyComputation();
  print('Done!');
} catch (e) {
  /* Handle exception... */
}

等待多个 Future

Waiting for multiple futures

有时代码逻辑需要调用多个异步函数,并等待它们全部完成后再继续执行。使用 Future.wait() 静态方法管理多个 Future 以及等待它们完成:

Sometimes your algorithm needs to invoke many asynchronous functions and wait for them all to complete before continuing. Use the Future.wait() static method to manage multiple Futures and wait for them to complete:

Future deleteLotsOfFiles() async =>  ...
Future copyLotsOfFiles() async =>  ...
Future checksumLotsOfOtherFiles() async =>  ...

await Future.wait([
  deleteLotsOfFiles(),
  copyLotsOfFiles(),
  checksumLotsOfOtherFiles(),
]);
print('Done with all the long steps!');

Stream

在 Dart API 中 Stream 对象随处可见,Stream 用来表示一些列数据。例如,HTML 中的按钮点击就是通过 stream 传递的。同样也可以将文件作为数据流来读取。

Stream objects appear throughout Dart APIs, representing sequences of data. For example, HTML events such as button clicks are delivered using streams. You can also read a file as a stream.

异步循环

Using an asynchronous for loop

有时,可以使用异步 for 循环 await for ,来替代 Stream API 。

Sometimes you can use an asynchronous for loop (await for) instead of using the Stream API.

思考下面示例函数。它使用 Stream 的 listen() 方法来订阅文件列表,传入一个搜索文件或目录的函数

Consider the following function. It uses Stream’s listen() method to subscribe to a list of files, passing in a function literal that searches each file or directory.

void main(List<String> arguments) {
  // ...
  FileSystemEntity.isDirectory(searchPath).then((isDir) {
    if (isDir) {
      final startingDir = Directory(searchPath);
      startingDir
          .list(
              recursive: argResults[recursive],
              followLinks: argResults[followLinks])
          .listen((entity) {
        if (entity is File) {
          searchFile(entity, searchTerms);
        }
      });
    } else {
      searchFile(File(searchPath), searchTerms);
    }
  });
}

下面是使用 await 表达式和异步 for 循环 (await for) 实现的等价的代码,看起来更像是同步代码:

The equivalent code with await expressions, including an asynchronous for loop (await for), looks more like synchronous code:

Future main(List<String> arguments) async {
  // ...
  if (await FileSystemEntity.isDirectory(searchPath)) {
    final startingDir = Directory(searchPath);
    await for (var entity in startingDir.list(
        recursive: argResults[recursive],
        followLinks: argResults[followLinks])) {
      if (entity is File) {
        searchFile(entity, searchTerms);
      }
    }
  } else {
    searchFile(File(searchPath), searchTerms);
  }
}

重要:

Important:

在使用 await for 前,确认这样能保持代码清晰,并希望获取所有 stream 的结果。例如,你通常并 会使用 await for 来监听 DOM 事件,因为 DOM 会发送无尽的流事件。如果在同一行使用 await for 注册两个 DOM 事件,那么第二个事件永远不会被处理。

Before using await for, make sure that it makes the code clearer and that you really do want to wait for all of the stream’s results. For example, you usually should not use await for for DOM event listeners, because the DOM sends endless streams of events. If you use await for to register two DOM event listeners in a row, then the second kind of event is never handled.

有关 await 的使用及 Dart 语言的相关信息,参考 Asynchrony support

For more information on using await and related Dart language features, see the asynchronous programming codelab.

监听流数据(stream data)

Listening for stream data

使用 await for 或者使用 listen() 方法监听 stream,来获取每个到达的数据流值:

To get each value as it arrives, either use await for or subscribe to the stream using the listen() method:

// Find a button by ID and add an event handler.
querySelector('#submitInfo').onClick.listen((e) {
  // When the button is clicked, it runs this code.
  submitData();
});

下面示例中,ID 为 “submitInfo” button 提供的 onClick 属性是一个 Stream 对象。

In this example, the onClick property is a Stream object provided by the “submitInfo” button.

如果只关心其中一个事件,可以使用,例如,firstlast,或 single 属性来获取。要在处理时间前对事件进行测试,可以使用,例如 firstWhere()lastWhere(),或 singleWhere() 方法。

If you care about only one event, you can get it using a property such as first, last, or single. To test the event before handling it, use a method such as firstWhere(), lastWhere(), or singleWhere().

如果只关心事件中的一个子集,可以使用,例如,skip()skipWhile()take()takeWhile(),和 where()

If you care about a subset of events, you can use methods such as skip(), skipWhile(), take(), takeWhile(), and where().

传递流数据(stream data)

Transforming stream data

常常,在使用流数据前需要改变数据的格式。使用 transform() 方法生成具有不同类型数据的流:

Often, you need to change the format of a stream’s data before you can use it. Use the transform() method to produce a stream with a different type of data:

var lines = inputStream
    .transform(utf8.decoder)
    .transform(LineSplitter());

上面例子中使用了两个 transformer 。第一个使用 utf8.decoder 将整型流转换为字符串流。接着,使用了 LineSplitter 将字符串流转换为多行字符串流。这些 transformer 来自 dart:convert 库(参考dart:convert section)。

This example uses two transformers. First it uses utf8.decoder to transform the stream of integers into a stream of strings. Then it uses a LineSplitter to transform the stream of strings into a stream of separate lines. These transformers are from the dart:convert library (see the dart:convert section).

处理错误和完成

Handling errors and completion

处理错误和完成代码方式,取决于使用的是异步 for 循环(await for)还是 Stream API 。

How you specify error and completion handling code depends on whether you use an asynchronous for loop (await for) or the Stream API.

如果使用的是异步 for 循环,那么通过 try-catch 来处理错误。代码位于异步 for 循环之后,会在 stream 被关闭后执行。

If you use an asynchronous for loop, then use try-catch to handle errors. Code that executes after the stream is closed goes after the asynchronous for loop.

Future readFileAwaitFor() async {
  var config = File('config.txt');
  Stream<List<int>> inputStream = config.openRead();

  var lines = inputStream
      .transform(utf8.decoder)
      .transform(LineSplitter());
  try {
    await for (var line in lines) {
      print('Got ${line.length} characters from stream');
    }
    print('file is now closed');
  } catch (e) {
    print(e);
  }
}

如果使用的是 Stream API,那么通过注册 onError 监听来处理错误。代码位���注册的 onDone 中,会在 stream 被关闭后执行。

If you use the Stream API, then handle errors by registering an onError listener. Run code after the stream is closed by registering an onDone listener.

var config = File('config.txt');
Stream<List<int>> inputStream = config.openRead();

inputStream
    .transform(utf8.decoder)
    .transform(LineSplitter())
    .listen((String line) {
  print('Got ${line.length} characters from stream');
}, onDone: () {
  print('file is now closed');
}, onError: (e) {
  print(e);
});

更多内容

More information

更多在 command-line 应用中使用 Future 和 Stream 的实例,参考 dart:io 概览 也可以参考下列文章和教程:

For some examples of using Future and Stream in command-line apps, see the dart:io tour. Also see these articles, codelabs, and tutorials:

dart:math - 数学和随机数

dart:math - math and random

dart:math 库(API reference)提供通用的功能,例如,正弦和余弦,最大值和最小值,以及数学常数,例如 pie。大多数在 Math 库中的功能是作为顶级函数实现的。

The dart:math library (API reference) provides common functionality such as sine and cosine, maximum and minimum, and constants such as pi and e. Most of the functionality in the Math library is implemented as top-level functions.

通过 import dart:math 来引入使用该库。

To use this library in your app, import dart:math.

import 'dart:math';

三角函数

Trigonometry

Math 库提供基本的三角函数:

The Math library provides basic trigonometric functions:

// Cosine
assert(cos(pi) == -1.0);

// Sine
var degrees = 30;
var radians = degrees * (pi / 180);
// radians is now 0.52359.
var sinOf30degrees = sin(radians);
// sin 30° = 0.5
assert((sinOf30degrees - 0.5).abs() < 0.01);

提示:

Note:

这些函数参数单位是弧度,不是角度!

These functions use radians, not degrees!

最大值和最小值

Maximum and minimum

Math 库提供 max()min() 方法:

The Math library provides max() and min() methods:

assert(max(1, 1000) == 1000);
assert(min(1, -1000) == -1000);

数学常数

Math constants

在 Math 库中可以找到你需要的数学常熟,例如,pie 等等:

Find your favorite constants—pi, e, and more—in the Math library:

// See the Math library for additional constants.
print(e); // 2.718281828459045
print(pi); // 3.141592653589793
print(sqrt2); // 1.4142135623730951

随机数

Random numbers

使用 Random 类产生随机数。可以为 Random 构造函数提供一个可选的种子参数。

Generate random numbers with the Random class. You can optionally provide a seed to the Random constructor.

var random = Random();
random.nextDouble(); // Between 0.0 and 1.0: [0, 1)
random.nextInt(10); // Between 0 and 9.

也可以产生随机布尔值序列:

You can even generate random booleans:

var random = Random();
random.nextBool(); // true or false

更多内容

More information

完整方法列表参考 Math API docs。在 API 文档中参考 num, int,double

Refer to the Math API reference for a full list of methods. Also see the API reference for num, int, and double.

dart:convert - 编解码JSON,UTF-8等

dart:convert - decoding and encoding JSON, UTF-8, and more

dart:convert 库(API reference)提供 JSON 和 UTF-8 转换器,以及创建其他转换器。 JSON 是一种用于表示结构化对象和集合的简单文本格式。 UTF-8 是一种常见的可变宽度编码,可以表示Unicode字符集中的每个字符。

The dart:convert library (API reference) has converters for JSON and UTF-8, as well as support for creating additional converters. JSON is a simple text format for representing structured objects and collections. UTF-8 is a common variable-width encoding that can represent every character in the Unicode character set.

dart:convert 库可以在 web 及命令行应用中使用。使用时,通过 import dart:convert 引入。

The dart:convert library works in both web apps and command-line apps. To use it, import dart:convert.

import 'dart:convert';

编解码JSON

Decoding and encoding JSON

使用 jsonDecode() 解码 JSON 编码的字符串为 Dart 对象:

Decode a JSON-encoded string into a Dart object with jsonDecode():

// NOTE: Be sure to use double quotes ("),
// not single quotes ('), inside the JSON string.
// This string is JSON, not Dart.
var jsonString = '''
  [
    {"score": 40},
    {"score": 80}
  ]
''';

var scores = jsonDecode(jsonString);
assert(scores is List);

var firstScore = scores[0];
assert(firstScore is Map);
assert(firstScore['score'] == 40);

使用 jsonEncode() 编码 Dart 对象为 JSON 格式的字符串:

Encode a supported Dart object into a JSON-formatted string with jsonEncode():

var scores = [
  {'score': 40},
  {'score': 80},
  {'score': 100, 'overtime': true, 'special_guest': null}
];

var jsonText = jsonEncode(scores);
assert(jsonText ==
    '[{"score":40},{"score":80},'
        '{"score":100,"overtime":true,'
        '"special_guest":null}]');

只有 int, double, String, bool, null, List, 或者 Map 类型对象可以直接编码成 JSON。 List 和 Map 对象进行递归编码。

Only objects of type int, double, String, bool, null, List, or Map (with string keys) are directly encodable into JSON. List and Map objects are encoded recursively.

不能直接编码的对象有两种方式对其编码。第一种方式是调用 encode() 时赋值第二个参数,这个参数是一个函数,该函数返回一个能够直接编码的对象第二种方式是省略第二个参数,着这种情况下编码器调用对象的 toJson() 方法。

You have two options for encoding objects that aren’t directly encodable. The first is to invoke encode() with a second argument: a function that returns an object that is directly encodable. Your second option is to omit the second argument, in which case the encoder calls the object’s toJson() method.

更多示例及 JSON 包相关链接,参考 JSON Support

For more examples and links to JSON-related packages, see Using JSON.

编解码 UTF-8 字符

Decoding and encoding UTF-8 characters

使用 utf8.decode() 解码 UTF8 编码的字符创为 Dart 字符创:

Use utf8.decode() to decode UTF8-encoded bytes to a Dart string:

List<int> utf8Bytes = [
  0xc3, 0x8e, 0xc3, 0xb1, 0xc5, 0xa3, 0xc3, 0xa9,
  0x72, 0xc3, 0xb1, 0xc3, 0xa5, 0xc5, 0xa3, 0xc3,
  0xae, 0xc3, 0xb6, 0xc3, 0xb1, 0xc3, 0xa5, 0xc4,
  0xbc, 0xc3, 0xae, 0xc5, 0xbe, 0xc3, 0xa5, 0xc5,
  0xa3, 0xc3, 0xae, 0xe1, 0xbb, 0x9d, 0xc3, 0xb1
];

var funnyWord = utf8.decode(utf8Bytes);

assert(funnyWord == 'Îñţérñåţîöñåļîžåţîờñ');

将 UTF-8 字符串流转换为 Dart 字符串,为 Stream 的 transform() 方法上指定 utf8.decoder

To convert a stream of UTF-8 characters into a Dart string, specify utf8.decoder to the Stream transform() method:

var lines =
    utf8.decoder.bind(inputStream).transform(LineSplitter());
try {
  await for (var line in lines) {
    print('Got ${line.length} characters from stream');
  }
  print('file is now closed');
} catch (e) {
  print(e);
}

使用 utf8.encode() 将 Dart 字符串编码为一个 UTF8 编码的字节流:

Use utf8.encode() to encode a Dart string as a list of UTF8-encoded bytes:

List<int> encoded = utf8.encode('Îñţérñåţîöñåļîžåţîờñ');

assert(encoded.length == utf8Bytes.length);
for (int i = 0; i < encoded.length; i++) {
  assert(encoded[i] == utf8Bytes[i]);
}

其他功能

Other functionality

dart:convert 库同样包含 ASCII 和 ISO-8859-1 (Latin1) 转换器。更多详情,参考 API docs for the dart:convert library。

The dart:convert library also has converters for ASCII and ISO-8859-1 (Latin1). For details, see the API reference for the dart:convert library.

dart:html - 基于浏览器应用

dart:html - browser-based apps

Use the dart:html library to program the browser, manipulate objects and elements in the DOM, and access HTML5 APIs. DOM stands for Document Object Model, which describes the hierarchy of an HTML page.

Other common uses of dart:html are manipulating styles (CSS), getting data using HTTP requests, and exchanging data using WebSockets. HTML5 (and dart:html) has many additional APIs that this section doesn’t cover. Only web apps can use dart:html, not command-line apps.

Note: For a higher level approach to web app UIs, use a web framework such as AngularDart.

To use the HTML library in your web app, import dart:html:

import 'dart:html';

Manipulating the DOM

To use the DOM, you need to know about windows, documents, elements, and nodes.

A Window object represents the actual window of the web browser. Each Window has a Document object, which points to the document that’s currently loaded. The Window object also has accessors to various APIs such as IndexedDB (for storing data), requestAnimationFrame (for animations), and more. In tabbed browsers, each tab has its own Window object.

With the Document object, you can create and manipulate Element objects within the document. Note that the document itself is an element and can be manipulated.

The DOM models a tree of Nodes. These nodes are often elements, but they can also be attributes, text, comments, and other DOM types. Except for the root node, which has no parent, each node in the DOM has one parent and might have many children.

Finding elements

To manipulate an element, you first need an object that represents it. You can get this object using a query.

Find one or more elements using the top-level functions querySelector() and querySelectorAll(). You can query by ID, class, tag, name, or any combination of these. The CSS Selector Specification guide defines the formats of the selectors such as using a # prefix to specify IDs and a period (.) for classes.

The querySelector() function returns the first element that matches the selector, while querySelectorAll()returns a collection of elements that match the selector.

  // Find an element by id (an-id).
  Element elem1 = querySelector('#an-id');

  // Find an element by class (a-class).
  Element elem2 = querySelector('.a-class');

  // Find all elements by tag (<div>).
  List<Element> elems1 = querySelectorAll('div');

  // Find all text inputs.
  List<Element> elems2 = querySelectorAll(
    'input[type="text"]',
  );

  // Find all elements with the CSS class 'class'
  // inside of a <p> that is inside an element with
  // the ID 'id'.
  List<Element> elems3 = querySelectorAll('#id p.class');

Manipulating elements

You can use properties to change the state of an element. Node and its subtype Element define the properties that all elements have. For example, all elements have classes, hidden, id, style, and title properties that you can use to set state. Subclasses of Element define additional properties, such as the href property of AnchorElement.

Consider this example of specifying an anchor element in HTML:

<a id="example" href="http://example.com">link text</a>

This <a> tag specifies an element with an href attribute and a text node (accessible via a text property) that contains the string “linktext”. To change the URL that the link goes to, you can use AnchorElement’s href property:

var anchor = querySelector('#example') as AnchorElement;
anchor.href = 'https://dart.dev';

Often you need to set properties on multiple elements. For example, the following code sets the hidden property of all elements that have a class of “mac”, “win”, or “linux”. Setting the hidden property to true has the same effect as adding display:none to the CSS.

  <!-- In HTML: -->
  <p>
    <span class="linux">Words for Linux</span>
    <span class="macos">Words for Mac</span>
    <span class="windows">Words for Windows</span>
  </p>
  // In Dart:
  final osList = ['macos', 'windows', 'linux'];
  final userOs = determineUserOs();

  // For each possible OS...
  for (var os in osList) {
    // Matches user OS?
    bool shouldShow = (os == userOs);

    // Find all elements with class=os. For example, if
    // os == 'windows', call querySelectorAll('.windows')
    // to find all elements with the class "windows".
    // Note that '.$os' uses string interpolation.
    for (var elem in querySelectorAll('.$os')) {
      elem.hidden = !shouldShow; // Show or hide.
    }
  }

When the right property isn’t available or convenient, you can use Element’s attributes property. This property is a Map<String, String>, where the keys are attribute names. For a list of attribute names and their meanings, see the MDN Attributes page. Here’s an example of setting an attribute’s value:

  elem.attributes['someAttribute'] = 'someValue';

Creating elements

You can add to existing HTML pages by creating new elements and attaching them to the DOM. Here’s an example of creating a paragraph (<p>) element:

  var elem = ParagraphElement();
  elem.text = 'Creating is easy!';

You can also create an element by parsing HTML text. Any child elements are also parsed and created.

  var elem2 = Element.html(
    '<p>Creating <em>is</em> easy!</p>',
  );

Note that elem2 is a ParagraphElement in the preceding example.

Attach the newly created element to the document by assigning a parent to the element. You can add an element to any existing element’s children. In the following example, body is an element, and its child elements are accessible (as a List<Element>) from the children property.

  document.body.children.add(elem2);

Adding, replacing, and removing nodes

Recall that elements are just a kind of node. You can find all the children of a node using the nodes property of Node, which returns a List<Node> (as opposed to children, which omits non-Element nodes). Once you have this list, you can use the usual List methods and operators to manipulate the children of the node.

To add a node as the last child of its parent, use the List add() method:

  querySelector('#inputs').nodes.add(elem);

To replace a node, use the Node replaceWith() method:

  querySelector('#status').replaceWith(elem);

To remove a node, use the Node remove() method:

  // Find a node by ID, and remove it from the DOM.
  querySelector('#expendable').remove();

Manipulating CSS styles

CSS, or cascading style sheets, defines the presentation styles of DOM elements. You can change the appearance of an element by attaching ID and class attributes to it.

Each element has a classes field, which is a list. Add and remove CSS classes simply by adding and removing strings from this collection. For example, the following sample adds the warning class to an element:

  var elem = querySelector('#message');
  elem.classes.add('warning');

It’s often very efficient to find an element by ID. You can dynamically set an element ID with the id property:

  var message = DivElement();
  message.id = 'message2';
  message.text = 'Please subscribe to the Dart mailing list.';

You can reduce the redundant text in this example by using method cascades:

  var message = DivElement()
    ..id = 'message2'
    ..text = 'Please subscribe to the Dart mailing list.';

While using IDs and classes to associate an element with a set of styles is best practice, sometimes you want to attach a specific style directly to the element:

  message.style
    ..fontWeight = 'bold'
    ..fontSize = '3em';

Handling events

To respond to external events such as clicks, changes of focus, and selections, add an event listener. You can add an event listener to any element on the page. Event dispatch and propagation is a complicated subject; research the details if you’re new to web programming.

Add an event handler using element.onEvent.listen(function), where Event is the event name and function is the event handler.

For example, here’s how you can handle clicks on a button:

  // Find a button by ID and add an event handler.
  querySelector('#submitInfo').onClick.listen((e) {
    // When the button is clicked, it runs this code.
    submitData();
  });

Events can propagate up and down through the DOM tree. To discover which element originally fired the event, use e.target:

  document.body.onClick.listen((e) {
    final clickedElem = e.target;
    // ...
  });

To see all the events for which you can register an event listener, look for “onEventType” properties in the API docs for Element and its subclasses. Some common events include:

  • change
  • blur
  • keyDown
  • keyUp
  • mouseDown
  • mouseUp

Using HTTP resources with HttpRequest

Formerly known as XMLHttpRequest, the HttpRequest class gives you access to HTTP resources from within your browser-based app. Traditionally, AJAX-style apps make heavy use of HttpRequest. Use HttpRequest to dynamically load JSON data or any other resource from a web server. You can also dynamically send data to a web server.

Getting data from the server

The HttpRequest static method getString() is an easy way to get data from a web server. Use await with the getString() call to ensure that you have the data before continuing execution.

  Future main() async {
    String pageHtml = [!await HttpRequest.getString(url);!]
    // Do something with pageHtml...
  }

Use try-catch to specify an error handler:

  try {
    var data = await HttpRequest.getString(jsonUri);
    // Process data...
  } catch (e) {
    // Handle exception...
  }

If you need access to the HttpRequest, not just the text data it retrieves, you can use the request() static method instead of getString(). Here’s an example of reading XML data:

  Future main() async {
    HttpRequest req = await HttpRequest.request(
      url,
      method: 'HEAD',
    );
    if (req.status == 200) {
      // Successful URL access...
    }
    // ···
  }

You can also use the full API to handle more interesting cases. For example, you can set arbitrary headers.

The general flow for using the full API of HttpRequest is as follows:

  1. Create the HttpRequest object.
  2. Open the URL with either GET or POST.
  3. Attach event handlers.
  4. Send the request.

For example:

  var request = HttpRequest();
  request
    ..open('POST', url)
    ..onLoadEnd.listen((e) => requestComplete(request))
    ..send(encodedData);

Sending data to the server

HttpRequest can send data to the server using the HTTP method POST. For example, you might want to dynamically submit data to a form handler. Sending JSON data to a RESTful web service is another common example.

Submitting data to a form handler requires you to provide name-value pairs as URI-encoded strings. (Information about the URI class is in the URIs section of the Dart Library Tour.) You must also set the Content-type header to application/x-www-form-urlencode if you wish to send data to a form handler.

  String encodeMap(Map data) => data.keys
      .map((k) => '${Uri.encodeComponent(k)}=${Uri.encodeComponent(data[k])}')
      .join('&');

  Future main() async {
    var data = {'dart': 'fun', 'angular': 'productive'};

    var request = HttpRequest();
    request
      ..open('POST', url)
      ..setRequestHeader(
        'Content-type',
        'application/x-www-form-urlencoded',
      )
      ..send(encodeMap(data));

    await request.onLoadEnd.first;

    if (request.status == 200) {
      // Successful URL access...
    }
    // ···
  }

Sending and receiving real-time data with WebSockets

A WebSocket allows your web app to exchange data with a server interactively—no polling necessary. A server creates the WebSocket and listens for requests on a URL that starts with ws://—for example, ws://127.0.0.1:1337/ws. The data transmitted over a WebSocket can be a string or a blob. Often, the data is a JSON-formatted string.

To use a WebSocket in your web app, first create a WebSocket object, passing the WebSocket URL as an argument:

  var ws = WebSocket('ws://echo.websocket.org');

Sending data

To send string data on the WebSocket, use the send() method:

  ws.send('Hello from Dart!');

Receiving data

To receive data on the WebSocket, register a listener for message events:

  ws.onMessage.listen((MessageEvent e) {
    print('Received message: ${e.data}');
  });

The message event handler receives a MessageEvent object. This object’s data field has the data from the server.

Handling WebSocket events

Your app can handle the following WebSocket events: open, close, error, and (as shown earlier) message. Here’s an example of a method that creates a WebSocket object and registers handlers for open, close, error, and message events:

  void initWebSocket([int retrySeconds = 1]) {
    var reconnectScheduled = false;

    print("Connecting to websocket");

    void scheduleReconnect() {
      if (!reconnectScheduled) {
        Timer(Duration(seconds: retrySeconds),
            () => initWebSocket(retrySeconds * 2));
      }
      reconnectScheduled = true;
    }

    ws.onOpen.listen((e) {
      print('Connected');
      ws.send('Hello from Dart!');
    });

    ws.onClose.listen((e) {
      print('Websocket closed, retrying in ' + '$retrySeconds seconds');
      scheduleReconnect();
    });

    ws.onError.listen((e) {
      print("Error connecting to ws");
      scheduleReconnect();
    });

    ws.onMessage.listen((MessageEvent e) {
      print('Received message: ${e.data}');
    });
  }

More information

This section barely scratched the surface of using the dart:html library. For more information, see the documentation for dart:html. Dart has additional libraries for more specialized web APIs, such as web audio, IndexedDB, and WebGL.

For more information about Dart web libraries, see the web library overview.

dart:io - 服务器和命令行应用程序的 I/O 。

dart:io - I/O for servers and command-line apps

The dart:io library provides APIs to deal with files, directories, processes, sockets, WebSockets, and HTTP clients and servers.

Important: Only Flutter mobile apps, command-line scripts, and servers can import and use dart:io, not web apps.

In general, the dart:io library implements and promotes an asynchronous API. Synchronous methods can easily block an application, making it difficult to scale. Therefore, most operations return results via Future or Stream objects, a pattern common with modern server platforms such as Node.js.

The few synchronous methods in the dart:io library are clearly marked with a Sync suffix on the method name. Synchronous methods aren’t covered here.

To use the dart:io library you must import it:

import 'dart:io';

Files and directories

The I/O library enables command-line apps to read and write files and browse directories. You have two choices for reading the contents of a file: all at once, or streaming. Reading a file all at once requires enough memory to store all the contents of the file. If the file is very large or you want to process it while reading it, you should use a Stream, as described in Streaming file contents.

Reading a file as text

When reading a text file encoded using UTF-8, you can read the entire file contents with readAsString(). When the individual lines are important, you can use readAsLines(). In both cases, a Future object is returned that provides the contents of the file as one or more strings.

Future main() async {
  var config = File('config.txt');
  var contents;

  // Put the whole file in a single string.
  contents = await config.readAsString();
  print('The file is ${contents.length} characters long.');

  // Put each line of the file into its own string.
  contents = await config.readAsLines();
  print('The file is ${contents.length} lines long.');
}

Reading a file as binary

The following code reads an entire file as bytes into a list of ints. The call to readAsBytes() returns a Future, which provides the result when it’s available.

Future main() async {
  var config = File('config.txt');

  var contents = await config.readAsBytes();
  print('The file is ${contents.length} bytes long.');
}

Handling errors

To capture errors so they don’t result in uncaught exceptions, you can register a catchError handler on the Future, or (in an async function) use try-catch:

Future main() async {
  var config = File('config.txt');
  try {
    var contents = await config.readAsString();
    print(contents);
  } catch (e) {
    print(e);
  }
}

Streaming file contents

Use a Stream to read a file, a little at a time. You can use either the Stream API or await for, part of Dart’s asynchrony support.

import 'dart:io';
import 'dart:convert';

Future main() async {
  var config = File('config.txt');
  Stream<List<int>> inputStream = config.openRead();

  var lines =
      utf8.decoder.bind(inputStream).transform(LineSplitter());
  try {
    await for (var line in lines) {
      print('Got ${line.length} characters from stream');
    }
    print('file is now closed');
  } catch (e) {
    print(e);
  }
}

Writing file contents

You can use an IOSink to write data to a file. Use the File openWrite() method to get an IOSink that you can write to. The default mode, FileMode.write, completely overwrites existing data in the file.

var logFile = File('log.txt');
var sink = logFile.openWrite();
sink.write('FILE ACCESSED ${DateTime.now()}\n');
await sink.flush();
await sink.close();

To add to the end of the file, use the optional mode parameter to specify FileMode.append:

var sink = logFile.openWrite(mode: FileMode.append);

To write binary data, use add(List<int> data).

Listing files in a directory

Finding all files and subdirectories for a directory is an asynchronous operation. The list() method returns a Stream that emits an object when a file or directory is encountered.

Future main() async {
  var dir = Directory('tmp');

  try {
    var dirList = dir.list();
    await for (FileSystemEntity f in dirList) {
      if (f is File) {
        print('Found file ${f.path}');
      } else if (f is Directory) {
        print('Found dir ${f.path}');
      }
    }
  } catch (e) {
    print(e.toString());
  }
}

Other common functionality

The File and Directory classes contain other functionality, including but not limited to:

  • Creating a file or directory: create() in File and Directory
  • Deleting a file or directory: delete() in File and Directory
  • Getting the length of a file: length() in File
  • Getting random access to a file: open() in File

Refer to the API docs for File and Directory for a full list of methods.

HTTP clients and servers

The dart:io library provides classes that command-line apps can use for accessing HTTP resources, as well as running HTTP servers.

HTTP server

The HttpServer class provides the low-level functionality for building web servers. You can match request handlers, set headers, stream data, and more.

The following sample web server returns simple text information. This server listens on port 8888 and address 127.0.0.1 (localhost), responding to requests for the path /dart. For any other path, the response is status code 404 (page not found).

Future main() async {
  final requests = await HttpServer.bind('localhost', 8888);
  await for (var request in requests) {
    processRequest(request);
  }
}

void processRequest(HttpRequest request) {
  print('Got request for ${request.uri.path}');
  final response = request.response;
  if (request.uri.path == '/dart') {
    response
      ..headers.contentType = ContentType(
        'text',
        'plain',
      )
      ..write('Hello from the server');
  } else {
    response.statusCode = HttpStatus.notFound;
  }
  response.close();
}

HTTP client

The HttpClient class helps you connect to HTTP resources from your Dart command-line or server-side application. You can set headers, use HTTP methods, and read and write data. The HttpClient class does not work in browser-based apps. When programming in the browser, use the dart:html HttpRequest class. Here’s an example of using HttpClient:

Future main() async {
  var url = Uri.parse('http://localhost:8888/dart');
  var httpClient = HttpClient();
  var request = await httpClient.getUrl(url);
  var response = await request.close();
  var data = await utf8.decoder.bind(response).toList();
  print('Response ${response.statusCode}: $data');
  httpClient.close();
}

More information

This page showed how to use the major features of the dart:io library. Besides the APIs discussed in this section, the dart:io library also provides APIs for processes, sockets, and web sockets. For more information about server-side and command-line app development, see the server-side Dart overview.

For information on other dart:* libraries, see the library tour.

总结

Summary

本页向您介绍了 Dart 内置库中最常用的功能。但是,并没有涵盖所有内置库。您可能想要查看的其他内容包括 dart:collectiondart:typed_data, ,以及特定于平台的库,如 Dart web development librariesFlutter libraries.

This page introduced you to the most commonly used functionality in Dart’s built-in libraries. It didn’t cover all the built-in libraries, however. Others that you might want to look into include dart:collection and dart:typed_data, as well as platform-specific libaries like the Dart web development libraries and the Flutter libraries.

您可以使用 pub 包管理 工具获得更多库。 collection, crypto, http, intl, 以及 test 以上只是简单的列举了一些可以通过 pub 安装的库。

You can get yet more libraries by using the pub package manager. The collection, crypto, http, intl, and test libraries are just a sampling of what you can install using pub.

要了解有关 Dart 语言的更多信息,请参考 language tour

To learn more about the Dart language, see the language tour.