http://dart.goodev.org/guides/libraries/library-tour
Numbers
dart:core 库定义了 num, int, 和 double 类,这些类 定义一些操作数字的基础功能。
使用 parse()
函数可以把字符串 转换为 整数或者浮点数。
num 类也定义了一个 parse() 函数,这个函数会尝试解析 为整数,如果无法解析为整数,则会解析为浮点数(double)。
对于整数,可以指定一个 radix
作为基数:
使用 toString()
函数 (由 Object 对象定义)来把整数或者浮点数 转换为字符串。使用 num 类的函数 toStringAsFixed()
可以限定 小数点的位数。如果要指定转换为字符串的有效位数, 则可以使用定义在 num 类的 函数 toStringAsPrecision()
:
更多信息,参考 API 文档中每个类的描述: int, double, 和 num。 另外还有 dart:math提供了关于数学运算的常用功能。
Strings and regular expressions(字符串和正则表达式)
Dart 中的字符串是一个不可变的 UTF-16 码元(code units)序列。 在语言预览中对 字符串有详细的介绍。 你可以使用正则表达式(RegExp 对象) 来搜索字符串中的内容或者 替换部分字符串。
String 类定义了一些函数 split()
, contains()
, startsWith()
, endsWith()
等来处理各种字符串操作。
Searching inside a string(在字符串内搜索)
可以在字符串内查找特定字符的位置,还可以 判断字符串是否以特定字符串开始和结尾。 例如:
Extracting data from a string(从字符串中提取数据)
可以从字符串中获取到单个的字符,单个字符可以是 String 也可以是 int 值。 准确来说,实际得到的是一个 UTF-16 code units; 对于码率比较大的字符,实际得到的是两个 code units,例如 treble clef 符号 (‘\u{1D11E}’) 。
还可以从字符串中提取一个子字符串,或者把字符串分割为 多个子字符串:
Converting to uppercase or lowercase(大小写转换)
字符串大小写转换是非常 简单的:
注意: 注意上面的转换方式对于某些语言是有问题的。例如对于土耳其语言 中的无点 I 的转换就是错误的。
Trimming and empty strings(裁剪和判断空字符串)
trim()
函数可以删除字符串前后的空白字符。使用 isEmpty
可以 判断字符串是否为空(长度为 0)。
Replacing part of a string(替换部分字符)
Strings 是不可变的对象,可以创建他们但是无法修改。 如果你仔细研究了 String API 文档,你会注意到并没有 函数可以修改字符串的状态。 例如,函数 replaceAll()
返回一个新的 String 对象而不是修改 旧的对象:
Building a string(创建字符串)
使用 StringBuffer 可以在代码中创建字符串。 只有当你调用 StringBuffer 的 toString()
函数的时候,才会创建一个 新的 String 对象。而 writeAll()
函数还有一个可选的参数来指定每个字符串的分隔符, 例如下面指定空格为分隔符:
Regular expressions(正则表达式)
RegExp 类提供了 JavaScript 正则表达式同样的功能。 正则表达式可以高效率的搜索和匹配 字符串。
还可以直接操作 RegExp 类。 Match 类提供了 访问正则表达式匹配到的内容。
More information(更多信息)
参考 String API 文档 来查看 String 类的所有 方法。同时还可以参考下面这些类的 api 文档: StringBuffer, Pattern, RegExp, 和 Match.
Collections
Dart 提供了一些核心的集合 API,包含 lists, sets, 和 maps。
Lists
在语言预览中已经介绍过如何 创建 lists了。另外还可以 使用 List 构造函数来创建 List 对象。 List 类来定义了一些函数可以添加或者删除里面的数据。
使用 indexOf()
来查找 list 中对象的索引:
排序一个 list 可以使用 sort()
函数。还可以提供一个用来排序 的比较方法。排序方法返回值 为:对于小的值 为 < 0;对于相同的值为 0 ;对于大的值为 > 0。 下面的示例使用由 Comparable 定义的 compareTo()
函数,该函数也被 String 实现了。
List 是泛型类型,所以可以指定 里面所保存的数据类型:
参考 List API 文档 来查看 list 的 所有函数。
Sets
Dart 中的 Set 是一个无序集合,里面不能保护重复的数据。 由于是无序的,所以无法通过索引来从 set 中获取数据:
使用 contains()
和 containsAll()
来判断 set 中是否包含 一个或者多个对象:
交际是两个 set 中都有的数据的子集:
详细信息, 参考 Set API 文档。
Maps
map 通常也被称之为 字典或者 hash ,也是一个无序的集合,里面 包含一个 key-value 对。map 把 key 和 value 关联起来可以 方便获取数据。和 JavaScript 不同的是, Dart objects 不是 maps。
下面是两种定义 map 对象的方式:
使用中括号来访问或者设置 map 中的数据, 使用 remove()
函数来从 map 中删除 key 和 value。
还可以获取 map 的所有 key 和 value:
containsKey()
判断 map 是否包含一个 key。由于 map 的 value 可以为 null, 所有通过 key 来获取 value 并通过 判断 value 是否为 null 来判断 key 是否存在是 行不通的。所以添加了一个判断 key 是否存在的函数:
map 还有一个 putIfAbsent()
函数来设置 key 的值,但是只有该 key 在 map 中不存在的时候才设置这个值,否则 key 的值保持不变。该函数需要 一个方法返回 value:
详细信息请参考 Map API 文档。
Common collection methods(常用的集合函数)
List, Set, 和 Map 上可以使用很多常用的集合函数。 Iterable 类定义了一些常用的功能, List 和 Set 实现了 Iterable 。
注意: 虽然 Map 没有实现 Iterable,但是 Map 的 keys
和 values
属性实现了 Iterable。
可以使用 isEmpty
函数来判断集合是否为空的:
使用 forEach()
函数可以对集合中的每个数据都应用 一个方法:
在 Map 上使用 forEach()
的时候,方法需要能 接收两个参数(key 和 value):
Iterables 也有一个 map()
函数,这个函数返回一个包含所有数据的对象:
注意: map()
函数返回的对象也是一个 Iterable,该对象是懒求值(lazily evaluated) 的,只有当访问里面的值的时候, map 的方法才被调用。
可以使用 map().toList()
或者 map().toSet()
来 强制立刻执行 map 的方法:
Iterable 的 where()
函数可以返回所有满足特定条件的数据。 any()
判断是否有数据满足特定条件, every()
判断是否所有数据都满足 特定条件。
更多信息请参考 Iterable API 文档,以及 List, Set, 和 Map 的文档。
URIs
Uri 类 提供了 编码和解码 URI(URL) 字符的功能。 这些函数处理 URI 特殊的字符,例如 &
和 =
。 Uri 类还可以解析和处理 URI 的每个部分,比如 host, port, scheme 等。
Encoding and decoding fully qualified URIs(编码解码URI)
要编码和解码除了 URI 中特殊意义(例如 /
, :
, &
, #
)的字符, 则可以使用 encodeFull()
和 decodeFull()
函数。这两个函数可以用来编码和解码整个 URI,并且保留 URI 特殊意义的字符不变。
注意上面 some
和 message
之间的空格被编码了。
Encoding and decoding URI components(编码解码URI组件)
使用 encodeComponent()
和 decodeComponent()
可以编码 和解码 URI 中的所有字符,特殊意义的字符(/
, &
, 和 :
等) 也会编码,
注意上面特殊字符也被编码了,比如 /
编码为 %2F
。
Parsing URIs
如果有个 Uri 对象或者 URI 字符串,使用 Uri 的属性 可以获取每个部分,比如 path
。使用 parse()
静态 函数可以从字符串中解析一个 Uri 对象:
Building URIs
使用 Uri()
构造函数可以从 URI 的 各个部分来构造一个 Uri 对象:
更多信息参考 Uri API 文档 。
Dates and times
DateTime 对象代表某个时刻。时区是 UTC 或者 本地时区。
一些构造函数可以创建 DateTime 对象:
millisecondsSinceEpoch
属性返回自从 “Unix epoch”—January 1, 1970, UTC 以来的毫秒数值:
使用 Duration 类可以计算两个日期之间的间隔, 还可以前后位移日期:
警告: 使用 Duration 来在 DateTime 对象上前后移动数天可能会有问题, 比如像夏令时等时间问题。如果要按照天数来位移时间,则 需要使用 UTC 日期。
更多详细信息参考 DateTime 和 Duration 的 API 文档。
Utility classes(工具类)
核心库还包含了一些常用的工具类,比如排序、 值映射以及遍历数据等。
Comparing objects(比较对象)
实现 Comparable 接口表明该对象可以相互比较,通常用来 排序。compareTo()
函数对于 小于的值返回 < 0 ; 相同的值返回 0 ; 大于的值返回 > 0、
Implementing map keys
Dart 中的每个对象都有一个整数 hash 码,这样每个对象都 可以当做 map 的 key 来用。但是,你可以覆写 hashCode
getter 来自定义 hash 码的实现,如果你这样做了,你也需要 同时覆写 ==
操作符。相等的对象(使用 ==
比较)的 hash 码应该一样。Hasm 码并不要求是唯一的, 但是应该具有良好的分布形态。
Iteration
Iterable 和 Iterator 类支持 for-in 循环。当你创建一个类的时候,继承或者实现 Iterable 可以 提供一个用于 for-in 循环的 Iterators。 实现 Iterator 来定义实际的遍历操作。
Exceptions
Dart 核心库定义了很多常见的异常和错误类。 异常通常是一些可以预知和预防的例外情况。 错误这是无法预料的并且不需要预防的情况。
下面是一些常见的错误:
- NoSuchMethodError
-
当在一个对象上调用一个该对象没有 实现的函数会抛出该错误。
- ArgumentError
-
调用函数的参数不合法会抛出这个错误。
抛出一个应用相关的异常是一种用来表明有错误发生的常见 方法。你还可以通过实现 Exception 接口来自定义 一些异常。
更多信息,请参考 Exceptions 和 Exception API 文档。
dart:async - asynchronous programming
异步编程通常使用回调函数,但是 Dart 提供了另外的 选择: Future 和 Stream 对象。 Future 和 JavaScript 中的 Promise 类似,代表在将来某个时刻会返回一个 结果。Stream 是一种用来获取一些列数据的方式,例如 事件流。 Future, Stream, 以及其他异步操作的类在 dart:async 库中。
注意: 你并不是都需要直接使用 Future 和 Stream。 Dart 语言有一些异步功能的关键字,例如 async
和 await
。 详细信息 请参考 异步支持。
dart:async 库在 web app 和命令行 app 都可以使用。 只需要导入 dart:async 即可使用:
Future
在 Dart 库中随处可见 Future 对象,通常异步函数返回的对象就是一个 Future。 当一个 future 执行完后,他里面的值 就可以使用了。
Using await
在直接使用 Future api 之前,你可以考虑先使用 await
。 使用 await
的表达式比直接使用 Future api 的代码要更加 容易理解。
例如下面的方法。使用 Future 的 then()
函数来 执行三个异步方法, 每个方法执行完后才继续执行后一个方法。
下面是使用 await 表达式实现的同样功能的代码, 看起来更像是同步代码,更加容易理解:
异步方法可以把 Future 中的错误当做 异常来处理。 例如:
重要: 异步方法(带有关键字 async 的方法)会返回 Future。 如果你不想让你的方法返回 future,则 不要使用 async 关键字。 例如,你可以在你的方法里面调用一个 异步方法。
关于使用 await
和相关 Dart 语言的其他特性,请参考 异步支持。
Basic usage
可以使用 then()
来在 future 完成的时候执行其他代码。例如 HttpRequest.getString()
返回一个Future,由于 HTTP 请求是一个 耗时操作。使用 then()
可以在 Future 完成的时候执行其他代码 来解析返回的数据:
使用 catchError()
来处理 Future 对象可能抛出的 各种异常和错误:
then().catchError()
模式就是异步版本的 try
-catch
。
重要: 确保是在 then()
返回的 Future 上调用 catchError()
, 而不是在 原来的 Future 对象上调用。否则的话,catchError()
就只能处理原来 Future 对象抛出的异常而无法处理 then()
代码 里面的异常。
Chaining multiple asynchronous methods
then()
函数返回值为 Future,可以把多个异步调用给串联起来。 如果 then()
函数注册的回调函数也返回一个 Future,而 then()
返回一个同样的 Future。如果回调函数返回的是一个其他类型的值, 则 then()
会创建一个新的 Future 对象 并完成这个 future。
上面的示例中,代码是按照如下顺序执行的:
costlyQuery()
expensiveWork()
lengthyComputation()
Waiting for multiple futures
有时候,你的算法要求调用很多异步方法,并且等待 所有方法完成后再继续执行。使用 Future.wait()
这个静态函数来管理多个 Future 并等待所有 Future 执行完成。
Stream
Stream 在 Dart API 中也经常出现,代表一些列数据。 例如, HTML 按钮点击事件就可以使用 stream 来表示。 还可以把读取文件内容当做一个 Stream。
Using an asynchronous for loop
有时候可以使用异步 for 循环(await for
)来 替代 Stream API。
例如下面的示例中,使用 Stream 的 listen()
函数来订阅 一些文件,然后使用一个方法参数来 搜索每个文件和目录。
下面是使用 await 表达式和异步 for 循环 实现的等价的代码, 看起来更像是同步代码:
重要: 在使用 await for
之前请确保使用之后的代码看起来确实是 更加清晰易懂了。例如,对于 DOM时间监听器通常 不会使用 await for
,原因在于 DOM 发送 无尽的事件流。 如果使用 await for
来在同一行注册两个 DOM 事件监听器, 则第二个事件在不会被处理。
关于使用 await
和相关 Dart 语言的其他特性, 请参考 异步支持。
Listening for stream data
要想在每个数据到达的时候就去处理,则可以选择使用 await for
或者 使用 listen()
函数来订阅事件:
上面的示例中, onClick
属性是 “submitInfo” 按钮提供的一个 Stream 对象。
如果你只关心里面其中一个事件,则可以使用这些属性: first
, last
, 或者 single
。要想在处理事件之前先测试是否满足条件,则 使用 firstWhere()
, lastWhere()
, 或者 singleWhere()
函数。
如果你关心一部分事件,则可以使用 skip()
, skipWhile()
, take()
, takeWhile()
, 和 where()
这些函数。
Transforming stream data
经常你需要先转换 stream 里面的数据才能使用。 使用 transform()
函数可以生产另外一个数据类型 的 Stream 对象:
上面的代码使用两种转换器(transformer)。第一个使用 UTF8.decoder 来把整数类型的数据流转换为字符串类型的数据流。然后使用 LineSplitter 把字符串类型数据流转换为按行分割的数据流。 这些转换器都来至于 dart:convert 库。 参考 dart:convert ) 了解详情。
Handling errors and completion
使用异步 for 循环 (await for
) 和使用 Stream API 的 异常处理情况是有 区别的。
如果是异步 for 循环,则可以 使用 try-catch 来处理异常。
在 stream 关闭后执行的代码位于异步 for 循环 之后。
如果你使用 Stream API,则需要 使用 onError
函数来处理异常。 stream 完成后执行的代码要通过 onDone
函数 来执行。
More information
关于在命令行应用中使用 Future 和 Stream 的更多示例,请参考 dart:io 里面的内容。 下面也是一些可以参考的文章和教程:
Asynchronous Programming: Futures
Futures and Error Handling
The Event Loop and Dart
Asynchronous Programming: Streams
Creating Streams in Dart
dart:math - math and random
Math 库提供了常见的数学运算功能,例如 sine 和 cosine, 最大值、最小值等,还有各种常量 例如 pi 和 e 等。Math 库中 的大部分函数都是顶级方法。
导入 dart:math 就可以使用 Math 库了。 下面的示例代码使用前缀 math
来引用库中的顶级 方法和常量:
Trigonometry
Math 库中提供了常见的三角运算功能:
注意: 上面这些函数是基于弧度的不是基于角度的。
Maximum and minimum
Math 库提供了 max()
和 min()
函数用来计算最大值和最小值:
Math constants
Math 库中提供各种数学常量,例如 pi, e 等。
Random numbers
使用 Random 类可以生成随机数。 在 Random 构造函数中还可以提供一个随机种子:
也可以生成随机的布尔值:
More information
详细的信息可以参考 Math API 文档 来了解。 还可以参考下面这些类的 API 文档 num, int, 和 double。
dart:html - browser-based apps
如果要和浏览器打交道则需要使用 dart:html 库, 访问 DOM 元素和使用 HTML5 API。 DOM 是 Document Object Model 的缩写,用来 描述 HTML 页面的结构。
dart:html 还可以用来操作样式表(CSS)、用 HTTP 请求 来获取数据,使用 WebSockets 来获取数据。 HTML5 (和 dart:html) 具有很多其他的 API 在这里并没有介绍。 只有 Web 应用可以使用 dart:html,命令行应用无法使用该库。
注意: 关于构建 Web 应用的更高层级的框架,请参考 Polymer Dart 和 Angular 2 for Dart。
在 web 应用中导入 dart:html 就可以使用 HTML 相关的功能了:
Manipulating the DOM
要使用 DOM 你需要了解 windows, documents, elements, 和 nodes 等概念。
一个 Window 对象代表 浏览器实际的窗口。每个窗口都有一个文档(Document)对象, 文档对象是当前正在加载的界面。Window 对象还可以访问各种 API,例如 用于存储数据的 IndexedDB、用于动画的 requestAnimationFrame 等。 在多窗口浏览器中,每个窗口(tab 也)都有 自己的 Window 对象。
使用 Document 对象, 可以创建和操纵 document 中的 Elements 对象。 注意 Document 本身也是一个 element,也是可以 被修改的。
DOM 模型是很多 Nodes 组成的树状结构。这些 nodes 通常 是 elements,但是也可以是 attributes、 text、 comments、 和其他 DOM 类型。 除了跟节点没有父节点以外,其他 DOM 中的节点都有一个 父节点,还有可能带有很多子节点。
Finding elements
在操作一个 element 之前,你需要先找到这个 element。 使用查询语法可以查找所需要的 element。
使用顶级方法 querySelector()
和querySelectorAll()
可以查找一个或者多个符合条件的 element。可以根据 ID、class、tag、name 或者 这些的组合来查询 element。 CSS 选择器 规范 定义了选择器的形式, 例如使用 # 前缀代表 ID,英文句号 (.) 代表 classes。
使用 querySelector()
方法可以获取第一个符合选择器要求的元素; 而 querySelectorAll()
返回所有符合 选择器要求的元素结合。
Manipulating elements
可以使用属性(properties)来修改 element 的状态。 Node 和子类型 Element 定义了所有 element 都具有的属性。例如, 所有 element 都有 classes
, hidden
, id
, style
, 和 title
属性,你可以使用这些属性来修改 element 的状态。 Element 的 子类还定义了其他属性,比如 AnchorElement 定义了 href
属性。
例如下面的示例在 HTML 中设置一个锚链接:
通常你需要在多个 element 上设置属性。例如,下面的示例在 所有 class 样式带有 “mac”, “win”, 或者 “linux” 的 element 上设置hidden
属性。设置 hidden
属性为 true 和 设置 CSS 样式 display:none
是同样的效果。
当属性不能访问或者不方便访问的时候,可以使用 Element 的 attributes
属性。 这个属性是一个 Map
,里面的 key 为属性名字。所有 HTML 元素的 属性名字以及意义,请参考 MDN Attributes 网页。下面是一个设置 属性值的示例:
Creating elements
还可以创建新的 element 然后添加到 HTML 页面的 DOM 中。下面的示例创建了一个 段落 (
) 元素:
使用 HTML 文本也可以创建 element。所包含的子元素 也一起被创建:
注意上面的 elem2 对象是一个 ParagraphElement 。
给新创建的 Element 指定一个父节点可以把这个 Element 添加到 DOM 中。 可以把 Element 添加到任何已经存在于 DOM 中的其他 Element 的 children 中。 例如,下面的示例,body
是一个 element,使用 children
属性来 访问该元素的所有子元素(返回的是一个 List
Adding, replacing, and removing nodes
之前说过,element 也是 node 的一种。使用 Node 的 nodes
属性可以 获取到当前 node 的所有子元素,nodes
返回的是 Listchildren
属性只包含 Element 类型的 nodes)。 获取到这个 Node list 后,就可以使用 List 的各种函数来 处理这些 Node 对象了。
使用 List 的add()
函数可以把一个 node 添加到所有子元素的 最后:
使用 Node 的 replaceWith()
函数可以替换一个 Node:
使用 Node 的 remove()
函数来删除 node:
Manipulating CSS styles
CSS(cascading style sheets 的缩写)定义了 DOM 元素的 UI 样式。 在一个 element 上附加 ID 和 class 属性可以修改 其应用的 CSS 样式。
没有 element 都有一个 classes
属性(field),该属性的类型为 List。 添加和移除上面的 CSS 类就是向这个集合中添加和删除字符串。 流入,下面的示例中给 element 添加了 warning
CSS 类样式。
通过 ID 来查找元素非常高效。通过 id
属性你可以动态给一个 Element 指定 一个 ID 值。
使用级联调用可以减少 需要编写的代码:
使用 ID 和 CSS 的 classes 来应用样式是最佳的方式,但是有时候 你还是希望直接在 element 上应用具体的样式,则 可以直接使用 style 属性:
Handling events
要响应像点击、聚焦等外部事件,你需要使用事件监听器。 在页面上的任何 element 上都可以注册事件监听器。 事件分发和传递是一个很复杂的议题: 如果你是 Web 开发新手, 请到 这里来 详细研究这个事件分发机制。
使用 *element*.on*Event*.listen(*function*)
来添加事件监听器, 这里的 *Event*
是事件的名字,而 *function*
是事件处理器。
例如,下面是处理按钮点击的事件:
事件可以通过 DOM 树来向上或者向下传递。 通过 e.target
可以获取是那个 element 触发该事件的:
要查看所有可以注册的事件名字,可以查看 Element 文档中的 “onEventType” 属性。 下面是一些常见的事件:
change
blur
keyDown
keyUp
mouseDown
mouseUp
Using HTTP resources with HttpRequest
HttpRequest 类是之前 大家耳熟能详的 XMLHttpRequest 的功能一样,使用该类 可以在 web 应用总访问 HTTP 资源。 一般而言, AJAX 风格的应用会很依赖 HttpRequest。使用 HttpRequest 来 动态的加载 JSON 数据或者其他资源。 还可以动态的向服务器发送数据。
下面的示例假设所有的资源都是来至于和当前脚本文件位于 同一个 web 服务器。由于浏览器的安全限制, HttpRequest 要使用 其他服务器的资源是比较麻烦的。如果你需要访问 其他服务器上的资源, 你需要使用 JSONP 技术或者 启用另外一个资源服务器的 CORS header。
Getting data from the server
HttpRequest 的静态函数 getString()
可以很方便的从服务器获取资源。 使用 await
来确保 getString()
调用资源返回后再 在继续执行后面的代码:
在 dart:convert 中会介绍 JSON API 相关的内容。
使用 try-catch 来指定异常处理代码:
如果除了返回的文本数据以外你还需要 访问 HttpRequest,你可以使用 request()
静态函数。下面 是一个读取 XML 数据的示例:
可以使用 full API 来处理各种情况。例如, 设置请求 header 信息。
下面是使用 HttpRequest full API 的常用流程:
- 创建 HttpRequest 对象。
- 使用
GET
或者POST
打开一个 URL。 - 添加事件处理器。
- 发送请求。
例如:
Sending data to the server
HttpRequest 还可以使用 HTTP POST 函数来向服务器发送数据。 例如,你可能希望动态的提交数据到服务器。 向 RESTful web 服务器发送 JSON 数据是一种非常常见的情况。
在表单处理中提交数据需要提供一个 name-value 数据对,该数据还需要 使用 URI 编码(关于 URI 类的信息请 参考 URIs 文档)。 如果要在表单处理器中提交数据则还 需要设置 Content-type
header 为 application/x-www-form-urlencode
。
Sending and receiving real-time data with WebSockets
WebSocket 可以让你的 web 应用和服务器持续的交互数据,不用 一直的轮询。创建 WebSocket 的服务器会监听 ws:// 开头的 URL, 例如 ws://127.0.0.1:1337/ws。 通过 WebSocket 发送的数据可以是字符串或者 blob。 通常都是使用 JSON 格式的字符串。
要在 web 应用中使用 WebSocket,需要先创建 WebSocket 对象,把 WebSocket URL 作为该对象的参数。
Sending data
使用 send()
函数向 WebSocket 发送数据:
Receiving data
要从 WebSocket 接收数据,需要注册一个事件 监听器:
消息事件处理函数的参数为 MessageEvent 对象。 该对象的 data
变量保存了服务器返回的数据。
Handling WebSocket events
你的应用可以处理如下的 WebSocket 事件:open, close, error, 和 (前面演示的) message。下面是演示各种事件 的 示例:
More information
上面只是简单的介绍了 dart:html 库。更多信息 请参考 dart:html。 Dart 还有一些 web 特殊领域的 api,例如 web audio, IndexedDB, 和 WebGL。
dart:io - I/O for command-line apps
dart:io 库 提供了一些和 文件、目录、进程、sockets、 WebSockets、和 HTTP 客户端以及服务器的 API。 只有命令行应用可以使用 dart:io 库,web app 无法使用。
一般而言,dart:io 库实现和提供的是异步 API。 同步函数很容易阻塞应用,后期扩展起来非常麻烦。 因此,大部分的操作返回值都是 Future 或者 Stream 对象, 如果你熟悉 Node.js 则对这种 模式会有所了解。
dart:io 里面也有一小部分同步方法,这些方法都使用 sync 前缀命名方法名字。 这里就不再介绍这些同步方法了。
注意: 只有命令行应用才能导入 dart:io
。
Files and directories
I/O 库可以让命令行应用读写文件和查看目录。 读取文件有两种方式:一次读完或者通过流的方式来读取。 一次读完需要把文件内容读到内存中,如果文件 非常大或者你希望一边读文件一边处理,则应该 使用 Stream, 在 流式读取文件中介绍。
Reading a file as text
对于编码为 UTF-8 的文本,可以使用函数 readAsString()
一次性 的读取整个文本。如果单行文字比较重要,则可以 使用 readAsLines()
来读取。 这两个函数返回一个 Future 对象,当文件 读取完的时候,可以从 Future 对象获取一个或者多个字符串。
Reading a file as binary
下面的示例把文件数据读取为字节流。 同样 readAsBytes()
函数返回值为 Future, 当读完文件后,可以从 Future 中获取数据。
Handling errors
在 Future 上注册一个 catchError
来处理异常, 还可以在 async 方法中使用 try-catch 来 处理异常:
Streaming file contents
使用 Stream 读取文件的时候, 使用 Stream API 或者 await for
可以一点点的读取, 详情参考 异步支持。
Writing file contents
使用 IOSink 可以往文件 写入内容。使用 File 的 openWrite()
函数获取到一个 IOSink。 默认的写模式为 FileMode.WRITE
,新写入的数据会完全覆盖 文件之前的内容。
如果想在文件末尾追加内容,则可以使用 mode
可选参数,参数取值 为 FileMode.APPEND
:
使用 add(List
函数可以写二进制数据到文件。
Listing files in a directory
查找目录中的所有文件和子目录是一个异步操作。 list()
函数返回一个 Stream,当遇到文件或者子目录的时候, Stream 就发射一个对象。
Other common functionality
File 和 Directory 类包含其他的一些文件操作, 下面只是一些常见的函数:
创建文件或者目录:
create()
in File and Directory删除文件或者目录:
delete()
in File and Directory获取文件的长度:
length()
in File随机位置访问文件:
open()
in File
参考 File 和 Directory 的 API 文档来 查看所有的函数。
HTTP clients and servers
dart:io 库提供了一些命令行应用可以用来访问 HTTP 资源 和运行 HTTP 服务器的类。
HTTP server
HttpServer 类 提供了用来建构 Web 服务器的底层方法。可以匹配 请求处理、设置 header、处理数据等。
下面的示例项目只能返回简单的文本信息。 服务器监听本机地址 127.0.0.1 的 8888 端口, 响应来自于 /languages/dart
路径的请求。所有其他的 请求都有默认的请求处理器处理(返回 404 页面没发现的错误提示)。
HTTP client
HttpClient 类可以 在命令行应用程序或者服务器应用程序中使用,用来请求 HTTP 资源。 可以设置请求头、HTTP 请求方式和读写 数据。HttpClient 无法在 web 应用中使用。 在 web 应用中可以使用 HttpRequest class。 下面是使用 HttpClient 的一个示例:
More information
除了上面提到的几个功能外,dart:io 库还包含 processes, sockets, 和 web sockets 等相关的 API。
dart:convert - decoding and encoding JSON, UTF-8, and more
dart:convert 库 里面有一些用来转换 JSON 和 UTF-8 的转换器,还可以自定义 新的转换器。 JSON 是非常流行的数据格式。 UTF-8 是一种非常流行的编码格式, 能够代表所有 Unicode 字符 集。
命令行应用和 web 应用都可以使用 dart:convert 库。 导入 dart:convert 就可以使用该库了。
Decoding and encoding JSON
使用 JSON.decode()
函数把 JSON 字符串解码为 Dart 对象:
使用 JSON.encode()
可以把 Dart 对象 编码为 JSON 字符串:
默认只支持 int、double、String、bool、null、List或者 Map(key 需要为 string) 这些类型转换为 JSON。 集合对象会使用递归的形式来转换每个对象。
对于默认不支持的对象,可以有两种选择: 一,调用 encode()
并指定第二个参数, 该参数是一个函数用来返回一个默认支持的对象; 二,不指定第二个参数,则会 调用该对象的 toJson()
函数。
Decoding and encoding UTF-8 characters
使用 UTF8.decode()
来解码 UTF8-encoded 字节流为 Dart 字符串:
如果是 stream 字节流则可以在 Stream 的 transform()
函数上指定 UTF8.decoder
:
使用 UTF8.encode()
把字符串编码为 UTF8 字节 流:
Other functionality
dart:convert 来包含转换 ASCII 和 ISO-8859-1(Latin1) 的转换器。详情请参考 dart:convert 库的 API 文档。
dart:mirrors - reflection
dart:mirrors 库提供了基本的反射支持。 使用 mirror 来查询程序的结构,也可以 在运行时动态的调用方法或者函数。
dart:mirrors 库在命令行和 web 应用中均可使用。 导入 dart:mirrors 即可开始使用。
警告: 使用 dart:mirrors 可能会导致 dart2js 生成的 JavaScript 代码 文件非常大!
目前的解决方式是在导入 dart:mirrors 之前添加一个 @MirrorsUsed
注解。 详情请参考 MirrorsUsed API 文档。由于 dart:mirrors 库依然还在 开发中,所以这个解决方案以后很有可能发生变化。
Symbols
mirror 系统使用 Symbol 类对象 来表达定义的 Dart 标识符名字。 Symbols 在混淆后的代码也可以 使用。
如果在写代码的时候,已经知道 symbol 的名字了,则可以使用 #符号名字 的方式直接使用。 直接使用的 symbol 对象是编译时常量,多次定义引用的是同一个对象。 如果名字不知道,则可以通过 Symbol 构造函数来 创建:
在混淆代码的时候,编译器可能使用更加简短的名字来替代原来的符号(symbol)名字。 要获取原来的 symbol 名字,使用MirrorSystem.getName()
函数。该函数 在代码混淆的情况下,也能返回正确的 symbol 名字。
Introspection
使用 mirror 功能来检查程序的结构。可以检查 类、库以及对象等。
下面的示例使用 Person 类:
在开始使用之前,需要在一个类或者对象上调用 reflect 函数来获取 到 mirror。
Class mirrors
在任何 Type 上面调用 reflect 函数来获取 ClassMirror :
也可以在实例上调用 runtimeType
获取该对象的 Type。
获取到 ClassMirror 后,就可以查询类的构造函数、成员变量、等信息。 下面是列出类的所有构造函数的示例:
下面是列出类的成员变量的示例:
详情请参考 ClassMirror 的 API 文档。
Instance mirrors
在对象上调用 reflect 函数可以获取到一个 InstanceMirror 对象。
如果你已经有个 InstanceMirror 对象了,但是想知道该对象反射的目标对象,则需要 调用 reflectee
。
Invocation
获取到 InstanceMirror 后,就可以调用里面的函数、getter和setter了。 详细信息请参考 API docs for InstanceMirror 的 API 文档。
Invoke methods
使用 InstanceMirror 的 invoke()
函数来调用对象的函数。 第一个参数为要调用的函数名字,第二个参数为该函数的 一个位置参数列表。第三个参数为可选参数,用来指定命名 参数。
Invoke getters and setters
使用 InstanceMirror 的 getField()
和 setField()
函数来 查询和设置对象的属性。