对于泛型想必不用多说,在我们自己写框架或封装时,经常会用到,Dart中泛型的使用基本上于Java差不多,在原理上由于Java泛型为泛型擦除,而Dart是运行时进行即使编译,所以Dart泛型是 固化的
类上使用了泛型后,我们在成员变量上使用,在创建实例时指定泛型类型:
class Cache<T> {
T value;
Cache(this.value);
}
main() {
Cache cache1 = Cache<String>("hi");
Cache cache2 = Cache<int>(123);
print(cache1.value);
print(cache2.value);
}
运行结果:
由于Dart支持var
方式定义变量,所以直观上来说,使用泛型并没有什么区别,方法上使用该泛型类型
class Cache<T> {
T value;
Cache(this.value);
T getCache() => value;
}
除了类上定义泛型,单独的方法中可以定义泛型,下面我们在transformValue
方法上定义一个泛型F
,并且通过一个transform
函数返回F
类型的结果,transform
函数接收一个T
类型参数,并返回一个F
类型结果,转换实现交由外部调用者实现
class Cache<T> {
T value;
Cache(this.value);
T getCache() => value;
// 将T类型的value转换为别的类型F
F transformValue<F>(F transform(T)) {
return transform(value);
}
}
main() {
Cache cache2 = Cache<int>(123);
print(cache2.value);
// 传入一个匿名函数,返回一个字符串
print(cache2.transformValue((value) {
return "hi,${value}";
}));
}
运行结果:
如果你想要定义多个泛型类型,只需要使用,
分割,类于方法都可以使用
class N<A, B, C> {}
moreGeneric<A, B, C, D>() {}
没有约束的泛型是可以传递任意类型的,有时我们希望对该类型进行一定的约束,如只能为某个类的子类,可以通过T extends OtherClass
对T
泛型进行约束,表示该泛型只能为OtherClass
的子类
class O {}
class Foo<T extends O> {
T value;
Foo(this.value);
}
main(){
// 报错提示
Foo foo1 = Foo<int>(123);
Foo foo2 = Foo<O>(O());
}
在foo1上会有报错提示:
Dart中,每个Dart文件都是一个库,使用文件名作为库名,使用library
关键字可以标识为一个库,但可以省略。
下面我们创建一个Dart文件:cacheModule.dart
,含有下面的代码:
library;
class Cache<T> {
T value;
Cache(this.value);
T getCache() => value;
// 将T类型的value转换为别的类型F
F transformValue<F>(F transform(T)) {
return transform(value);
}
}
导入后,我们可以直接使用库中的可见内容
import 'package:study1/cacheModule.dart';
main(){
Cache cache = Cache<String>("hi");
print(cache.value);
}
库中含有仅仅内部使用的成员,可以使用_
前缀标识,使用后,外部无法使用该成员
library;
...
// 内部类
class _hideClz{}
// 内部方法
_hideFuntion() {}
如两个库module1.dart
和module2.dart
中,都含有一个P
类
class P {}
导入时使用as
给库设置别名后,可以解决冲突:
import 'package:study1/module1.dart';
import 'package:study1/module2.dart' as m2;
main() {
P p = P();
m2.P p2 = m2.P();
}
在导入时,可以通过show
指定导入库的内容,也可以通过hide
隐藏导入的内容
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
有时库使用的时机较少,为减少初始化时间,延迟加载库可以在使用时才真正的导入库,使用 deferred as
关键字来标识需要延时加载的代码库:
import 'package:greetings/hello.dart' deferred as hello;
Dart对异步的支持比较友好,使用简单,主要分为两大类:Future
和Stream
Future
和Java中的概念类似,在方法后面使用async
关键字修饰,调用该方法会返回一个Future
对象。
Dart中代替了Future
对象方法的调用,使用关键字await
进行取代,在调用异步方法前使用await
修饰后,异步线程会等待 await
异步方法执行完毕后继续执行。同时,await
的使用需要在async
作用域下
// async修饰后,会返回Future对象
Future<String> getAsyncInfo() async {
return "hi";
}
main() async {
// await需在async作用域下调用,会等待异步方法执行完毕
var result = await getAsyncInfo();
print("异步调用结果:$result");
}
运行结果:
Stream
是专门为上下流作准备的,你可以理解为观察者模式,上流为一个异步任务,并不定时往下流发送内容,下流接收内容并作处理
异步循环语法:await for (var v in stream){}
创建一个文件:
下面我们打开该文件,在async
下使用await for
获取流中的数据:
import 'dart:convert';
import 'dart:io';
main() async {
var config =
File('C:/Users/tyqhc/Documents/flutterworkspace/study1/lib/config.txt');
Stream<List<int>> inputStream = config.openRead();
// 将流转为utf-8,逐行读取
var lines =
inputStream.transform(utf8.decoder).transform(const LineSplitter());
await for (final v in lines) {
print(v);
}
}
运行结果:
Stream对象还有内置API,可供读取和监听流
使用listen
,获取流数据:
import 'dart:convert';
import 'dart:io';
main() {
var config =
File('C:/Users/tyqhc/Documents/flutterworkspace/study1/lib/config.txt');
Stream<List<int>> inputStream = config.openRead();
var lines =
inputStream.transform(utf8.decoder).transform(const LineSplitter());
// listen获取流数据
lines.listen((event) {
print(event);
});
}
除了获取流外,还可以通过transformer
对流数据进行转换,上面我们也使用过:
var lines =
inputStream.transform(utf8.decoder).transform(const LineSplitter());
生成器可以生成一连串的值,方式分为同步于异步
同步生成器在方法后使用sync*
标识,在函数体中使用yield
来传递值,返回一个Iterable
对象:
Iterable<int> generateInts() sync* {
for (var i = 0; i < 10; i++) {
yield i;
}
}
main() {
for (final i in generateInts()) {
print(i);
}
}
异步生成器在方法后使用async*
标识,在函数体中同样使用yield
来传递值,返回一个Stream
对象:
Stream<int> generateIntsStream() async* {
for (var i = 0; i < 10; i++) {
yield i;
}
}
main() async {
await for (final i in generateIntsStream()) {
print(i);
}
}
Dart中定义注解方式和类一样,使用时加上@
即可:
// 作为注解的类
class MyAnnotation {
final String name;
const MyAnnotation(this.name);
}
("hi")
class MyClz {
("hi val")
var value;
MyClz(this.value);
}