Skip to content

Latest commit

 

History

History
1112 lines (824 loc) · 25.9 KB

02. Dart库.md

File metadata and controls

1112 lines (824 loc) · 25.9 KB

Dart库

dart:core 内置类, 集合和其他核心功能. 这个库自动导入到每个Dart程序中
dart:async 支持异步编程, 如Future和Stream类
dart:math 数学常量和函数, 加上随机数的生成
dart:convert JSON和UTF-8数据的编码和反编码

核心库 dart:core - numbers, collections, strings, and more

Printing to the console

print()方法中传入一个参数(任一对象), 然后打印对象的字符串值(toString()的返回值)

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

Numbers

num, int 和 double 类, 有同一个基础的工具来处理数字

使用int和double的parse()方法, 将string转int

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

使用num的parse()方法, 将string转int或者double

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

使用radix参数指定int的基数

assert(int.parse('42', radix: 16) == 66);
  • 使用toString()方法, 将int或者double转成string.
  • 使用 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);

字符串和正则表达式 Strings and regular expressions

Dart中的字符串是一个不可变的UTF-16序列. 可以使用正则表达式(RegExp 对象)来搜索字符串中的内容或者替换部分字符串

String类定义了split(), contains(), startsWith(), endsWith()等方法

字符串中搜索 Searching inside a string
// 是否包含
assert('Never odd or even'.contains('odd'));

// 是否以什么开头
assert('Never odd or even'.startsWith('Never'));

// 是否以什么结尾
assert('Never odd or even'.endsWith('even'));

// 获取字符串所在的位置
assert('Never odd or even'.indexOf('odd') == 6);
从字符串中提取数据 Extracting data from a string

提取子字符串, 将字符串分成一个子字符串数组

// 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
// Convert to uppercase.
assert('structured web apps'.toUpperCase() ==
    'STRUCTURED WEB APPS');

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

该方法不适用所有语言. 如土耳其语可能转换失败...

空字符串裁剪 Trimming and empty strings

使用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);
替换部分字符串 Replacing part of a string

字符串是不可变的, 只能创建不能更改. 如replaceAll()方法返回了一个新的字符串.

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

// greetingTemplate didn't change.
assert(greeting != greetingTemplate);
StringBuffer Building a string

使用StringBuffer生成一个字符串. StringBuffer不会生成一个新的字符串对象. 除非调用toString()方法. 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.');
正则表达式 Regular expressions
// 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类进行匹配

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
}

Collections

lists, sets, and maps

Lists

可以使用字面量直接初始化一个List, 也可以使用任意一个List的构造函数进行初始化.

// 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.length == 0);

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(). 提供一个排序函数来比较两个对象. (This sorting function must return < 0 for smaller, 0 for the same, and > 0 for bigger)

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

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

指定list中的元素类型

// This list should contain only strings.
var fruits = List<String>();

fruits.add('apples');
var fruit = fruits[0];
assert(fruit is String);
sets

set是一个无序的唯一的元素集合.

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() 来检查集合中是否包含某些元素

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

交集

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

类似字典或哈希表, 无序的键值对集合.

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

add, get, set, 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));

获取所有key值和value值

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() 来判断是否包含某个key. map值可能为空, 因此通过key取值是否为空来判断key是否存在.

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

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

putIfAbsent(), 只能map中不存在该key时, 才会添加到map中

var teamAssignments = {};
teamAssignments.putIfAbsent(
    'Catcher', () => pickToughestKid());
assert(teamAssignments['Catcher'] != null);
通用集合方法

isEmpty 和 isNotEmpty

var coffees = [];
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'));
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.
});

map()方法, 返回一个集合对象

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

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

map()返回的可迭代的对象是懒加载的. 当访问对象中的某个元素时, map()函数才会调用.

如果要强制立刻执行map()函数, 使用map().toList() 或 map().toSet()

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

使用Iterable中的where()方法, 来获取所有符合条件的元素. 使用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));

URIs

URI类提供函数来编码/解码URIs字符串(URL)

编码和解码全部有意义的URIs Encoding and decoding fully qualified URIs

encodeFull() 和 decodeFull(), 编码和解码除特殊含义(/, :, &, #)外的所有字符

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);
Encoding and decoding URI components

encodeComponent() 和 decodeComponent(), 编码和解码所有字符, 连同特殊字符(/, :, &, #)一起

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);
解析URIs Parsing URIs
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');
构建URIs Building URIs
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对象

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

Duration类, 计算两个日期的时间差, 也可以获取相差几天前后的日期

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.

工具类 Utility classes

比较对象 Comparing objects

实现Comparable接口来比较两个对象, 通常用来排序(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

每个对象都提供一个integer类型的哈希值, 可以做为map中的key. 也可以冲下hashCode的getter方法来自定义的哈希值. 如果重写哈希值, 也需要重写== operator. 通过 == 方法判断对象是都有同一个哈希值. 哈希值不一定要是唯一的

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

Iterable 和 Iterator 支持 for-in 循环. 当创建的类想要提供Iterators在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 (var process in Processes()) {
    // Do something with the process.
  }
}

Exceptions

Exceptions和Errors

常见的一对errors

  • NoSuchMethodError 找不到方法
  • ArgumentError 传入方法的参数错误

通过实现Exception的声明来自定义异常

class FooException implements Exception {
  final String msg;

  const FooException([this.msg]);

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

异步编程 dart:async - asynchronous programming

异步编程通常使用回调函数. Dart提供一种不同方案: Future 和 Stream 对象. Future预设在未来某个时间会提供一个结果值. Stream用来获取一系列值(如事件).

异步编程, 没有必要一定要使用Future 或 Stream, 也可以使用async 和 await关键字

导入库 (dart 2.1中不需要导入)

import 'dart:async';

Future

Future对象, 通常通过异步方法返回. 当预期执行完毕, 它的值就可以使用了.

Using await

使用Future的then()方法, 异步处理

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

另一种实现方案, 使用await表达式异步处理, 看起来更像同步代码

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

异步函数可以捕获Futures异常

var entryPoint = await findEntryPoint();
try {
  var exitCode = await runExecutable(entryPoint, args);
  await flushThenExit(exitCode);
} catch (e) {
  // Handle the error...
}
基本使用 Basic usage

then(), Future执行完后, 提供字符串结果值, 然后执行then后面的代码

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

catchError(), 捕获Future对象可能抛出的异常

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

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

Chaining multiple asynchronous methods

按一定顺序执行多个异常函数. 如果一个回调的返回值是Future, 那么它注册的then()返回同一个Future. 如果该回调返回其他类型的值, then()会创建一个带该值的Future.

Future result = costlyQuery(url);
result
    .then((value) => expensiveWork(value))
    .then((_) => lengthyComputation())
    .then((_) => print('Done!'))
    .catchError((exception) {
  /* Handle exception... */
});
以上代码执行顺序如下:
costlyQuery()
expensiveWork()
lengthyComputation()

使用await

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

如果等待多个异步结果值, 才能继续执行代码. 可以使用Future.wait()的静态方法来管理多个Futures, 等待他们执行完毕.

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

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

Stream

Stream对象表示一系列数据. 如Html的按钮点击事件就是通过steams来传递的. 读取文件时也是通过steam传递的.

异步for循环 Using an asynchronous for loop

使用Stream的listen()方法订阅文件列表

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

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);
  }
}
监听流数据 Listening for stream data

await for 或 listen()

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

onClick属性是 “submitInfo”按钮提供的流对象

如果只需要监听一个事件, 可以使用 first, last, or single. 如果处理事件前想要做一些校验, 可以使用firstWhere(), lastWhere(), or singleWhere()

事件的子集, skip(), skipWhile(), take(), takeWhile(), and where()

流数据转换 Transforming stream data

使用transform()转换流的数据格式

var lines = inputStream
    .transform(utf8.decoder)
    .transform(LineSplitter());
Handling errors and completion

异步for循环, 使用try-catch捕获异常

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监听错误

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

...dart:io tour

dart:math - math and random

Math库中包含一些常用功能, 如.正弦/余弦, 最大值/最小值, 常量pi, e. 大部分Math库中函数都是顶级函数.

导入库

import 'dart:math';

三角计算 Trigonometry

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

这些方法使用的是弧度而不是角度.

最大值, 最小值 Maximum and minimum

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

数学常量 Math constants

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

随机数 Random numbers

通过Random类实现随机数

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

随机布尔值

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

More information

...

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

JSON 和 UTF-8 转换

导入convert库

import 'dart:convert';

JSON编码和解码 Decoding and encoding JSON

使用jsonDecode(), 将JSON字符串转Dart对象

// 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(), 将JSON字符串转Dart对象

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, or Map (key值必须为字符串). List 和 Map 会递归编码.

不能直接编码的对象有两种处理方式. 第一种是调用encode(), 传入第二个参数(一个返回能够直接编码的对象的函数). 另一种是省略第二个参数, 这种情况下会调用对象的toJson()方法.

Decoding and encoding UTF-8 characters

utf8.decode()

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ñåţîöñåļîžåţîờñ');

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

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

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