Dart学习之核心

496 阅读7分钟

打印

print打印对象的信息,如果对象是非字符串,则调用对象的toString()方法。

print(object);

断言

assert(true);

数值

数值的原型类是num,包含两个子类型整数int和浮点数float,数值包括二进制、八进制、十进制、十六进制以及科学计数法,十六进制由0x开头表示。

字符串转数值

// 整数无法转换浮点数
int.parse("42"); // 42
int.parse("0x42"); // 66
int.parse("19.1"); // FormatException: Invalid radix-10 number (at character 1)

// 整数转换时指定进制
int.parse('42', radix: 16); // 66

// 浮点数是转不了十六进制
double.parse("42"); // 42.0
double.parse("19.1"); // 19.1
double.parse("0x42"); // FormatException: Invalid double
double.parse("1.2e+2"); // "120.0"

// 使用num转换是最安全的,但是需要在使用的时候断言类型
num.parse("42") as int; // 42
num.parse("0x42") as int ; // 66
num.parse("19.1") as double; // 19.1

数值转字符串

42.toString(); // "42"
19.1.toString(); // "19.1"
// 十六进制在转成字符串的时候,会先转成整型
0x42.toString(); // "62"
// 浮点型转字符串时指定精度
123.456.toStringAsFixed(2); // "123.45"
// 转成科学计数法
123.456.toStringAsPrecision(2); // "1.2e+2"

字符串

字符串在dart里面是一串UTF-16编码的不可变序列。字符串原型类String提供了查询、搜索、修改等一系列基础功能,并可以配合正在表达式进行高阶处理。

"ab" + "cde"; // abcde
"ab" * 3; // ababab
"ab" == "cde";  // false

查询

"abcde".indexOf('a'); // 0
"abcde".contains("bc"); // true
"abcde".startWith("a"); //true
"abcde".endWith("a"); // false
"abcde".substring(2, 4); // "cd"
"abcde".codeUnitAt(1); // 98

修改

"the".toUpperCase(); // "THE"
"THE".toLowerCase(); // "the"
" the ".trim(); // "the"
"a good idea".split(" "); // ["a", "good", "idea"]

使用正则

"this is a string.".contains(RegExp(r'\d+')); // false
"Current time is 2021-12-17 14:00.".replaceAll(RegExp(r'\d+'), 'XX'); // "Current time is XX-XX-XX XX:XX."

构建字符串 使用StringBuffer以编码方式生成字符串,在调用toString()之前StringBuffer不会生成新的String对象。

var sb = StringBuffer();
sb..write('this ')
  ..writeAll(['is', 'a', 'string'], ' ')
  ..write('.');
sb.toString(); // "this is a string."

集合

集合包括列表(List)、无序列表(Set)和键值映射(Map),集合的都实现了迭代的功能,可以调用迭代的方法。

列表(List)

列表可以通过字面量直接声明,也可以List类构造方法构造。

var data = <String>[];
data.isEmpty(); // true
data.add('dog'); // ['dog']
data.addAll(['cat', 'fox']); // ['dog', 'cat', 'fox']
data.length; // 3
data.indexOf('cat'); // 1
data.removeAt(1); // ['dog', 'fox']
data.clear();

// 使用构造方法
var data = List(); // 这个构造函数以及被遗弃了,建议使用命名构造函数
var numbers = List.filled(5, 0); // [0, 0, 0, 0, 0]
numbers.add("6"); // Error: The argument type 'String' can't be assigned to the parameter type 'int'

无序列表(Set)

无序列表是一个没有顺序且元素唯一的集合,由于没有顺序,也就没有根据索引获取元素。

var data = <String>{};
data.add('gold'); // {'gold'}
data.addAll(['titanium', 'xenon']); // {'gold', 'titanium', 'xenon'}
// 重复添加只会保存一个
data.add('gold'); // {'gold', 'titanium', 'xenon'}
data.length; // 3
data.remove('gold'); // {'titanium', 'xenon'}
data.contains('xenon'); // true
data.containsAll(['titanium', 'xenon']); // true

// 使用构造方法
var data = Set<String>();
var data = Set.from(['titanium', 'xenon']);

键值映射(Map)

映射,通常称为字典或哈希,是键值对的无序集合。映射将键与某个值相关联以便于检索。映射的键和值的集合都是迭代。键是唯一的,重复添加会进行值覆盖。

// 构造方式
var data = Map();
var data = Map<int, String>();
var data = {
	1: "Tom",
	2: "Kelly"
}
data.keys; // (1, 2)
data.values; // (Tom, Kelly)
data.length; // 2 
data[1]; // "Tom"
data.containsKey(1); // true
data.putIfAbsent(3, () => "Jimmy"); // {1: Tom, 2: Kelly, 3: Jimmy}
data.addAll({4: "Henry", 5: "Cathy"}); // {1: Tom, 2: Kelly, 3: Jimmy, 4: Henry, 5: Cathy}

URI

URI提供一些列方法来编码和解码URL字符串。

var url = "https://www.baidu.com?s=flutter dart";
var encoded = Uri.encodeFull(url); // https://www.baidu.com?s=flutter%20dart
Uri.decodeFull(encoded); // https://www.baidu.com?s=flutter dart

var encoded = Uri.encodeComponent(url); // https%3A%2F%2Fwww.baidu.com%3Fs%3Dflutter%20dart
Uri.decodeComponent(encoded); // https://www.baidu.com?s=flutter dart

var uri =Uri.parse('https://www.baidu.com/foo/bar#frag');
uri.scheme; // https
uri.host; // www.baidu.com
uri.path; // /foo/bar
uri.fragment; // frag
uri.origin; // https://www.baidu.com

var uri = Uri(
	scheme: 'https',
	host: 'www.baidu.com',
	path: '/foo/bar',
	fragment: 'frag');
uri.toString();  // https://www.baidu.com/foo/bar#frag

时间

时间戳是从1970-01-01 00:00:00:000开始计算的。

// 获取当前时间
DateTime.now(); // 2021-12-20 16:23:48.685248
DateTime(2000); // 2000-01-01 00:00:00.000
DateTime(2000, 1, 2); // 2000-01-02 00:00:00.000
DateTime.utc(2000); // 2000-01-01 00:00:00.000Z
DateTime.fromMillisecondsSinceEpoch(946684800000, isUtc: true); // 2000-01-01 00:00:00.000Z
DateTime.parse('2000-01-01T00:00:00Z'); // 2000-01-01 00:00:00.000Z
DateTime.utc(1970).millisecondsSinceEpoch; // 0

var y2k = DateTime.utc(2000);
var y2001 = y2k.add(const Duration(days: 366));// 2001-01-01 00:00:00.000Z
var december2000 = y2001.subtract(const Duration(days: 30)); // 2000-12-02 00:00:00.000Z
december2000.year; // 2000
december2000.month; // 12

var duration = y2001.difference(y2k);
duration.inDays; // 366

功能类

核心提供了一系列功能类,用来实现排序、映射值以及迭代。

对象比较

class Line implements Comparable<Line> {
  final int length;
  const Line(this.length);
  @override
  int compareTo(Line other) => length - other.length;
	@override
	String toString() => length.toString();
}

var l1 = line(1);
var l2 = line(2);
l1.compareTo(l2); // -1

var data = [Line(4), l1, l2];
data.sort(); // [1, 2, 4];

// 修改compareTo(Line other) => other.length - length;
data.sort(); // [4, 2, 1];

迭代 实现迭代能力需要实现一个迭代器,然后继承IterableBase并注入迭代器来获得迭代的能力,获得迭代能力后,就可以用forin进行遍历。

// 进度模型
class Process {
  var current = 0;
  Process(this.current);
  @override
  String toString() => current.toString();
}
// 实现进度迭代器
class ProcessIterator implements Iterator<Process> {
  var _i = 0;
  @override
  Process get current => Process(_i);

  @override
  bool moveNext() {
    _i++;
    return _i < 5;
  }
}
// 创建可迭代进度
class Processes extends IterableBase<Process> {
  @override
  Iterator<Process> get iterator => ProcessIterator();
}
// 遍历进度
for (var p in Processes()) {
	print(p);
}
// output:
// 1
// 2
// 3
// 4

异常

在核心库中,提供了一些列的常用异常和错误。也可以通过实现Exception来实现自定义异常

class FooException implements Exception {
  final String? msg;

  const FooException([this.msg]);

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

throw FooException(); 
// Unhandled exception:
// FooException

异步

在dart中使用Future和Stream来实现异步编程,其中Future类似Promise一样,在未来的某个时间返回值。而Stream提供了一种方式获取一个序列值。异步编程需要导入aysnc库。

import 'dart:async';

Future await必须在aysnc函数中使用,异步函数必须返回Future来声明,其中T为返回数据的类型。

Future<void> runInFuture1() async {
  sleep(Duration(seconds: 2));
  print('runInFuture1');
}

Future<void> runInFuture2() async {
  sleep(Duration(seconds: 2));
  print('runInFuture2');
}

Future<void> run() async {
  await runInFuture1();
  print('running');
  await runInFuture2();
  print('run over');
}

print('start');
run();
print('over');
// output:
// start
// runInFuture1
// over
// running
// runInFuture2
// run over

// 不是await的回调方式,then返回的对象依然是Future类型的
run().then((value) => null);

// 异常捕获
try{
	await run();
}catch(e){}
// catchError返回的对象依然是Future类型的
run().then((value) => null).catchError((e) => null);

// Future.wait([])管理多个异步函数
Future.wait([runInFuture1(), runInFuture2()]);

Stream Steam主要用于各种事件和文件流等,比如HTML的dom事件。

Future<void> searchFiles(searchPath) async {
  if (await FileSystemEntity.isDirectory(searchPath)) {
    final startingDir = Directory(searchPath);
	   // 使用await for遍历目录下所有文件
    await for (final entity in startingDir.list()) {
      if (entity is File) {
        print(entity);
      }
    }
  }
}
// 文件读取
Future<void> readFileAwaitFor() async {
	var config = File('config.txt');
	Stream<List<int>> inputStream = config.openRead();
	// 对流数据进行转换,类似pipe功能
	var lines = inputStream
      .transform(utf8.decoder)
      .transform(const LineSplitter());
	// 流异常捕获
 	try {
    await for (final line in lines) {
      print('Got ${line.length} characters from stream');
    }
    print('file is now closed');
 	} catch (e) {
    print(e);
 	}
	// 使用回调模式
	lines.listen((String line){
		print('Got ${line.length} characters from stream');
	}, onDone:(){
		print('file is now closed');
	}, onError:(e){
		print(e);
	})
}	

数学

提供一些常用的处理数学问题的能力。需要导入math库。

import 'dart:math';

常量值

print(e); // 2.718281828459045
print(pi); // 3.141592653589793
print(sqrt2); // 1.4142135623730951

三角函数

sin(pi / 2); // 1.0
cos(pi); // -1.0

最大值和最小值

max(1, 1000); // 1000
min(1, -1000); // -1000

随机数

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

转化

转化库提供了JSON和UTF-8以及一些其他编码的转化。需要导入convert库。

import 'dart:convert';

JSON

var json = '''
  {
    "age":10, 
    "name": "Tommy"
  }
''';
jsonDecode(json); // {age: 10, name: Tommy}

var scores = [
	{'score': 40},
	{'score': 80}
];
jsonEncode(scores); // [{"score":40},{"score":80}]

UTF-8

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
];
utf8.decode(utf8Bytes); // Îñţérñåţîöñåļîžåţîờñ

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

IO

IO库提供了一系列API去处理文件、目录、进程、sockets、WebSockets和HTTP请求。IO库只能在非web的Flutter应用、命令行脚本和服务端应用。需要导入IO库。

import 'dart:io';

文件和目录 在IO库中,提供了一系列能力来处理文件和目录的读取和写入。

var config = File('config.txt');

// 读取整个文件
var stringContents = await config.readAsString();
print('The file is ${stringContents.length} characters long.');

// 分行读取
var lines = await config.readAsLines();
print('The file is ${lines.length} lines long.');

// 按二进制读取
var contents = await config.readAsBytes();
print('The file is ${contents.length} bytes long.');

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

HTTP 在IO库中提供了一些列类来访问HTTP资源和运行HTTP服务。

// 处理请求
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();
}
// 监听请求
final requests = await HttpServer.bind('localhost', 8888);
await for (final request in requests) {
	processRequest(request);
}

// 发起请求
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();