Dart学习笔记(36):Emulating Function仿真函数

Emulate也有模仿之意,Emulating Function可以理解成模拟函数
但翻译成仿真函数,瞬间高大上起来,中国汉字博大精深!

回归正题,本文将介绍如何定义Dart类,使它的行为像函数一样。

1、call()方法

下面的例子中,我们有一个普通的类WannabeFunction,它定义了一个名为call()的方法。

class WannabeFunction {
  call(int a, int b) => a + b;
}

方法call()有点特殊,定义call()方法之后,Dart会假定类是在动态地模拟一个函数。如果该方法有两个整型参数,它允许我们如下使用WannabeFunction的实例:

var wf = new WannabeFunction();
wf(3, 4); // 7

上面的例子相当平常,并没有什么价值,还不如直接写一个函数。但是,某些情况下这个特性非常有用。这也是Dart语言的核心设计思想、理念。

  • 对于一个对象,最重要的是它的行为。如果对象a与对象b有一个兼容的程序接口,则a可以代替b。
  • 任何一类对象的接口都可以被其它相应定义的对象模拟。

它是怎样运行的?

当对x(a1, …, an)求值的时候,在支持相应参数的情况下,如果它是一个标准的函数,它会以正常的方式被调用。如果并不是标准函数,则会调用call()

否则,noSuchMethod()被调用。noSuchMethod()的默认实现会检查该方法是否是因为企图使用call()而被调用,如果是这样的问题,建议使用闭包,以获取有用的错误信息。

2、apply()方法

Function类使用下面的签名来定义静态方法apply()

static apply(Function function,
                      List positionalArguments,
                      [Map<Symbol, dynamic> namedArguments]);

apply()允许函数以通常方式被调用。最后面的参数是位置参数,仅在使用命名参数调用函数时需要,它将参数名映射到参数值。需要注意的是,名称是通过Symbol来进行描述的。

3、Symbol

你可以从字符串创建Symbol

new Symbol('myFavoriteMethodName');

如果可以的话,尽量创建Symbol常量对象:

const Symbol('myFavoriteMethodName');

使用常量Symbol时,dart2js可以有效缩小代码。

4、函数类型

另一个问题是,用户定义的函数类如何与类型系统相关联。为了完全地模拟函数,我们希望它们成为恰当的函数类型的成员:

typedef BinaryFunction(a,b);
...
new WannabeFunction() is BinaryFunction; // true

因此,如果对象的类有一个call()方法,并且该方法是函数类型的成员,我们则判定此对象是一个函数类型的成员。

5、与Mirror和noSuchMethod()进行交互

在Dart中,对于未明确在你的Class继承链中定义的方法,你可以通过覆盖noSuchMethod(),来制定对象对这些方法如何作出反应。这里有一个例子,表明在noSuchMethod()中如何使用函数模拟:

noSuchMethod(Invocation invocation) =>
  invocation.memberName == #foo ? Function.apply(baz,
                             invocation.positionalArguments,
                             invocation.namedArguments)
                        : super.noSuchMethod(invocation);

第一个分支处理你希望将参数转发到其它函数的情况。如果你知道baz不需要任何命名参数,那么代码可以替换为Function.apply(baz, invocation.positionalArguments)。第二个分支简单地转发到标准的noSuchMethod()实现,这是常见的、通用的模式。

对于noSuchMethod()的参数只有一个Invocation。关于Invocation的布尔属性所辨认的方法调用的句法形式,如下表所示:

调用方法的形式
x.y x.y = e x.y(…)
isMethod false false true
isGetter true false false
isSetter false true false
isAccessor true true false

本文出自“Dart语言中文社区”,允许转载,转载时请务必以超链接形式标明文章原始出处
本文地址:
http://www.cndartlang.com/941.html

发表评论

登录后才能评论