以下是本人对Dart语法和机制探索的代码,对于有其他编程语言基础(和Dart的语法最像的是Java)的朋友而言,看懂这段200行的代码就基本会Dart的常用语法了。
可惜csdn的markdown不支持Dart,高亮有一点问题,这里采用了js的高亮。将就着看吧。
import 'dart:async';
import 'dart:mirrors';
// 没有public修饰,通过下划线开头的命名控制访问
class Father {
// 成员变量
// 字符串填充可用美元符,带大括号可以用长表达式,不带大括号只能填充单个变量名
// as 用于类型强制转换
String memberVariable = "some text ${print('assigning to member by initialization') as Null}";
// 计算属性getter,使用时相当于一个成员变量,但仅限读取,例如String something = this.computed + "suffix";
// 单表达式作为返回值的函数可以写成箭头形式
get computed => "$memberVariable and some other ${print("calling getter") as Null}";
// setter 计算属性setter,使用时相当于一个成员变量,但仅限写入,例如this.computed = "new text"
set computed(String value) => print('calling setter'); // 字符串用单/双引号均可
// 实例方法
instanceMethod(String parameter) {
print("calling instance method");
try {
double x = 7 / 2; // 浮点数除法
int y = 7 ~/ 2; // 整数除法
if (x != y) { throw Error(); }
} on Error /* 捕捉类型,可选*/ catch (error/* 存储异常对象的变量名,必选 */, stacktrace /* 存储调用栈对象的变量,可选 */) {
print(error);
print(stacktrace);
rethrow; // 重新抛出异常
} finally { print("in finally scope"); }
}
// static member 静态成员,下划线开头为private,外部不可见
static Father _staticMember = null;
// static method 静态方法
static staticMethod(String parameter) => print("calling static method");
// default constructor 构造函数,未定义任何构造函数时会隐式声明无参的默认构造函数
Father() {print("calling default constructor");}
// named constructor 命名构造函数
// this.memberVariable 作为参数,一键搞定成员赋值
Father.named(this.memberVariable) {print("calling named constructor");}
// factory constructor 工厂构造函数,可以不返回新实例
factory Father.factoryConstructor(String parameter) {
if (Father._staticMember == null) {
Father._staticMember = new Father.named(parameter); // new 是可选的,也可以写成Father.staticMember = Father.named(parameter);
}
return _staticMember; // 和Java一样,同一个类里可以省略不写类名访问静态字段
}
}
// mixin 混入
mixin SomeMixIn {
// mixin 不能有构造函数,其余与类基本一致
void mixinMethod() {
final message = "do"; // final只可以修饰变量和成员变量
const detail = "something"; // const用于声明编译时常量
// final和const修饰都可以推断变量的类型
print(message + detail);
}
}
// Dart的interface关键字已被删除,但所有类都对应一个隐式接口,固可用抽象类代替接口声明
// 由此也可以写出诸如 class StepFather implemets Father {...} 的代码
abstract class Interface {
// 抽象方法不需要加abstract修饰
abstractMethod();
}
class Son extends Father /* 单继承 */ with SomeMixIn /* 多混入 */ implements Interface /* 多实现 */ {
// 构造函数无法被继承,显式调用父类构造函数需要这样写
Son(): super(){}
Son.named(String paramter): super.named(paramter) {}
// override 重写
@override
instanceMethod(String parameter) {
print("calling override method");
try {
super.instanceMethod(parameter); // 调用父类方法
} catch(e) {}
}
// 可以利用混入实现一些代码的复用,或者用于“代替”多继承
void someMethod() => this.mixinMethod();
// 实现抽象方法
@override
abstractMethod() => print("abstract method implementation");
}
// 全局变量,属于package的命名空间
// {}作为表达式是空Map的语法糖,如果想解释成Set需要有元素,如{"a"}
// dynamic用于声明动态的类型
Map<Type, dynamic> instanceOf = {
// 类名也是全局变量,类型是Type
Father: Father() // Father()是new Father()的省略写法
};
// 定义函数作为一种类型
typedef TypeToMethodMirrorFunction = MethodMirror Function(Type);
// 全局函数,属于package的命名空间
MethodMirror getConstructor(Type type) {
// 函数reflectClass 来自包 dart:mirrors
var classMirror = reflectClass(type); // var 声明变量能将变量的类型推断为表达式的类型
Map<Symbol, DeclarationMirror> declarations = classMirror.declarations; // 手动声明类型也可以,但是会长一点
MethodMirror constructor; // 不初始化为null
// 迭代器循环
for (var item in declarations.entries) {
print(item);
// 元数据反射:item.value.metadata
var value = item.value;
// 实例类型判断用is而不是instanceof,相反逻辑用is!
if (value is MethodMirror) {
if (value.constructorName == Symbol.empty) {
// 跳过默认构造函数
continue;
}
if (value.isConstructor) {
constructor = value;
break;
}
}
}
return constructor;
}
// 使用定义过的类型来声明变量
TypeToMethodMirrorFunction anotherName = getConstructor;
// 反射实例
reflectDemo() {
// Map插入/读取键值是对通过索引而不是set(key, value)/get(key)
// []是List的语法糖
instanceOf[Son] = reflectClass(Son).newInstance(Symbol.empty, []); // 使用默认构造函数实例化
var constructor = anotherName(Son);
// 断言,非调试模式会被忽略,可附加断言失败的信息
assert(constructor != null && constructor.isConstructor, "constructor var is not constructor!");
InstanceMirror instanceMirror = reflectClass(Son)
.newInstance(constructor.constructorName, ["parameter"]);
Father father = instanceMirror.reflectee // 此处类型转换是dynamic转换成Father,运行时可能会出错
..instanceMethod("parameter") // 级联调用,可以非常方便地访问第一个表达式的成员
..computed += "nonsense"; // 级联调用也可以调用getter和setter
print(constructor.parameters); // 获得反射出方法的参数列表
// 通过反射对成员变量赋值
reflect(father).setField(#computed, "new value"); // #computed是Symbol("computed")的语法糖
print(
// 函数式迭代
instanceOf.entries.firstWhere(
(MapEntry<Type, dynamic> entry) { // anonymous function 匿名函数,参数类型可不声明,因为在这里参数的类型能够被推断
return entry.value.runtimeType == Father;
}
)
);
}
// 异步实例,异步函数应当返回Futrue,但在函数体内的return语句可直接返回Futrue泛型变量的类型的值,而不需要创建Future
// 命名参数x和hasDefault,hasDefault是带默认值的命名参数
Future<int> asyncAdd({int x, int hasDefault = 0}) async {
print("actual hasDefault: ${hasDefault}");
return ++x; // 也可以写 return Future.microtask(()=>++x);
}
// 可选位置参数,不声明类型默认为dynamic,p2是带默认值的可选位置参数
Future<void> asyncDemo([p1, dynamic p2 = "string"]) async {
onSuccess(int v) => print("async call success with $v") as Null; // 返回值需要不为void才能作为Futrue.then/catchError的回调函数
onError(dynamic e) => print("async call error with:\n$e") as Null;
// 不传递x,++x产生空指针异常
int x = await asyncAdd().then(onSuccess).catchError(onError);
print("async function returned $x");
// 命名参数的传递方式
x = await asyncAdd(x: 114514, hasDefault: 1919).then(onSuccess).catchError(onError);
print("async function returned $x");
}
// 生成器实例
generatorDemo() {
for(int result in generator()) { // 同步生成器可以使用for-in迭代,因为本质是Iterable
print("generator generated ${result}");
}
Stream<int> stream = asyncGenerator(10); // 异步生成器返回流,可以附加监听函数
stream.listen((value) => print("stream value: $value"));
}
Iterable<int> generator() sync* {
for(var item in [1,2,3]) {
yield item;
}
yield* subGenerator(); // 相当于将某个Iterable对象的迭代生成逐个yield
}
Iterable<int> subGenerator() sync* {
yield -1;
yield -2;
}
// 异步生成器
Stream<int> asyncGenerator(int count) async* {
if (count == 0) { return; }
yield count--;
yield* asyncGenerator(count);
}
// 主函数,执行入口
main(List<String> args) {
reflectDemo();
Future.value(asyncDemo()).then((v){}).catchError((){}); // 先同步后异步,因此输出在后面
generatorDemo();
}
运行输出:
assigning to member by initialization
calling default constructor
assigning to member by initialization
calling default constructor
MapEntry(Symbol("instanceMethod"): MethodMirror on 'instanceMethod')
MapEntry(Symbol("someMethod"): MethodMirror on 'someMethod')
MapEntry(Symbol("abstractMethod"): MethodMirror on 'abstractMethod')
MapEntry(Symbol("Son"): MethodMirror on 'Son')
MapEntry(Symbol("Son.named"): MethodMirror on 'Son.named')
assigning to member by initialization
calling named constructor
calling override method
calling instance method
Instance of 'Error'
#0 Father.instanceMethod (file:///c:/Coding/Playgrounds/playground.dart:21:21)
#1 Son.instanceMethod (file:///c:/Coding/Playgrounds/playground.dart:72:13)
#2 reflectDemo (file:///c:/Coding/Playgrounds/playground.dart:133:21)
#3 main (file:///c:/Coding/Playgrounds/playground.dart:198:3)
#4 _startIsolate. (dart:isolate-patch/isolate_patch.dart:305:32)
#5 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
in finally scope
calling getter
calling setter
[ParameterMirror on 'paramter']
calling setter
MapEntry(Father: Instance of 'Father')
actual hasDefault: 0
generator generated 1
generator generated 2
generator generated 3
generator generated -1
generator generated -2
async call error with:
NoSuchMethodError: The method '+' was called on null.
Receiver: null
Tried calling: +(1)
async function returned null
actual hasDefault: 1919
async call success with 114515
async function returned null
stream value: 10
stream value: 9
stream value: 8
stream value: 7
stream value: 6
stream value: 5
stream value: 4
stream value: 3
stream value: 2
stream value: 1