在 Dart 中,声明为类的一部分的实例方法与其他函数(如闭包和静态函数)之间存在差异。
实例方法是唯一可以访问this
. 从概念上讲,它们是类描述的一部分,而不是对象。也就是说,当你进行方法调用时,o.foo()
Dart 首先提取o
. 然后它foo
在类描述中搜索(如果需要,递归遍历超类)。最后,它将找到的方法应用于this
set to o
。
除了能够调用对象(o.foo()
)上的方法之外,还可以获得绑定闭包:(o.foo
没有用于调用的括号)。然而,这是至关重要的,这种形式只是(<args>) => o.foo(<args>)
. 也就是说,这只是创建了一个新的闭包,该闭包捕获o
并将对它的调用重定向到实例方法。
整个设置有几个重要的后果:
您可以撕下实例方法并获得绑定闭包。的结果o.foo
自动绑定到o
. 无需自己绑定(但也无法将其绑定到不同的实例)。在您的示例中,这是有效的方式one.getMyId
。您实际上得到了以下关闭:() => one.getMyId()
相反。
无法向对象添加或删除方法。您需要更改类描述,这是(故意)不支持的。
var f = o.foo;
意味着你总是得到一个新的关闭。这意味着您不能将此绑定闭包用作哈希表中的键。例如,register(o.foo)
后跟unregister(o.foo)
很可能不起作用,因为每个 o.foo 都会不同。您可以通过尝试轻松看到这一点print(o.foo == o.foo)
。
您不能将方法从一个对象转移到另一个对象。无论您尝试访问实例方法,它们都将始终被绑定。
看看你的例子:
print('one ${caller(one.getMyId)}'); //one 1
print('two ${caller(two.getMyId)}'); //two 2
print('one ${callerJustForThree(one.getMyId)}'); //NoSuchMethod Exception
这些行等效于:
print('one ${caller(() => one.getMyId())}');
print('two ${caller(() => two.getMyId())}');
print('one ${callerJustForThree(() => one.getMyId())}';
内部callerJustForThree
:
callerJustForThree(fn){
var three = new IDable(3);
three.fn();
}
给定的参数fn
被完全忽略。在最后一行做的时候,Dart 会找到(which is )three.fn()
的类描述,然后在里面搜索。由于它没有找到一个,它会调用回退。参数被忽略。three
IDable
fn
noSuchMethod
fn
如果要根据某个参数调用实例成员,可以将最后一个示例重写如下:
main() {
...
callerJustForThree((o) => o.getMyId());
}
callerJustForThree(invokeIDableMember){
var three = new IDable(3);
invokeIDableMember(three);
}