dart 方法调用上下文

Dan*_*son 2 scope dart

我使用下面的内容来查看 dart 如何调用传入其他方法的方法,以查看传入方法将/可以在什么上下文下调用。

void main() {

  var one = new IDable(1);
  var two = new IDable(2);

  print('one ${caller(one.getMyId)}');             //one 1
  print('two ${caller(two.getMyId)}');             //two 2
  print('one ${callerJustForThree(one.getMyId)}'); //NoSuchMethod Exception

}

class IDable{
  int id;
  IDable(this.id);

  int getMyId(){
    return id;
  }
}

caller(fn){
  return fn();
}

callerJustForThree(fn){
  var three = new IDable(3);
  three.fn();
}
Run Code Online (Sandbox Code Playgroud)

那么 manager 如何在没有上下文的情况下caller调用其参数ie ,以及为什么无法调用为其定义了该函数的对象传递的参数?fnone.fn()callerJustForThreefn

Flo*_*sch 5

在 Dart 中,声明为类的一部分的实例方法与其他函数(如闭包和静态函数)之间存在差异。

实例方法是唯一可以访问this. 从概念上讲,它们是类描述的一部分,而不是对象。也就是说,当您执行方法调用时,o.foo()Dart 首先提取o. 然后它在类描述中搜索foo(如果需要,递归地遍历超类)。最后它应用找到的方法并将this其设置为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
Run Code Online (Sandbox Code Playgroud)

这些行相当于:

 print('one ${caller(() => one.getMyId())}');
 print('two ${caller(() => two.getMyId())}');
 print('one ${callerJustForThree(() => one.getMyId())}';
Run Code Online (Sandbox Code Playgroud)

里面callerJustForThree

callerJustForThree(fn){
  var three = new IDable(3);
  three.fn();
}
Run Code Online (Sandbox Code Playgroud)

给定的参数fn被完全忽略。当在最后一行执行时, Dart 会找到(即)three.fn()的类描述,然后在其中进行搜索。由于它找不到,它将调用后备。该参数被忽略。threeIDablefnnoSuchMethodfn

如果您想根据某个参数调用实例成员,您可以重写最后一个示例,如下所示:

main() {
  ...
  callerJustForThree((o) => o.getMyId());
}

callerJustForThree(invokeIDableMember){
  var three = new IDable(3);
  invokeIDableMember(three);
}
Run Code Online (Sandbox Code Playgroud)