dart方法调用上下文

时间:2013-05-08 22:03:15

标签: 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();
}

那么caller经理如何在没有上下文fn的情况下调用其参数one.fn(),以及为什么callerJustForThree无法调用传入fn在为其定义了该函数的对象上?

2 个答案:

答案 0 :(得分:4)

在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()而不是。{/ p>

  • 无法向对象添加或删除方法。您需要更改类描述,这是(有意)不支持的。

  • 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。在最后一行中执行three.fn()时,Dart会找到three的类描述(IDable),然后在其中搜索fn。由于它没有找到,它会调用noSuchMethod后备。 fn参数被忽略。

如果要根据某个参数调用实例成员,可以按如下方式重写最后一个示例:

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

callerJustForThree(invokeIDableMember){
  var three = new IDable(3);
  invokeIDableMember(three);
}

答案 1 :(得分:0)

我会试着解释,这不一定是我的力量。如果我写的东西不可理解,请随时给我一个大喊。

将方法视为普通对象,也像其他变量一样。

当您调用caller(one.getMyId)时,您实际上并没有传递对类定义方法的引用 - 您传递了特定于one的方法“object”。

callerJustForThree中,您传递实例one的相同方法“对象”。但你不要叫它。如果您的方法调用范围中的对象fn,则调用实例fn的对象three,而不是存在,因为您没有在上课。

使用常规变量考虑此代码:

void main() {
  var one = new IDable(1);
  var two = new IDable(2);
  caller(one.id);
  caller(two.id);
  callerJustForThree(one.id);
}

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

caller(param){
  print(param);
}

callerJustForThree(param){
  var three = new IDable(3);
  print(three.id); // This works
  print(param);   // This works, too
  print(three.param); // But why should this work?
}

这是完全相同的概念。将您的回调视为正常变量,一切都有意义。至少我希望如此,如果我解释得足够好。