dart方法调用上下文 [英] dart method calling context

查看:233
本文介绍了dart方法调用上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用下面的例子来看看dart调用方法是如何传递给其他方法来查看方法中传递的上下文是什么/

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

那么调用方管理器调用其无参数 one.fn()的参数 fn ,为什么 callJustForThree 无法调用一个具有为其定义的函数的对象 fn 中的传递


<在Dart中,在作为类的一部分声明的实例方法和其他函数(如闭包和静态函数)之间有一个区别。



实例方法是唯一可以访问 this (除了构造函数)的方法。从概念上讲,它们是类描述的一部分,而不是对象。也就是说,当你做一个方法调用 o.foo() Dart首先提取 o 的类类型。然后它在类描述中搜索 foo (如果需要,递归地遍历超类)。最后,它应用找到的方法 this 设置为 o



除了能够调用对象上的方法( o.foo()),也可以得到一个绑定的闭包: o .foo (不带调用的括号)。然而,这是至关重要的,这种形式只是语法糖为(< args>)=> o.foo(< args>)。也就是说,这只是创建一个新的闭包,捕获 o 并将对它的调用重定向到实例方法。



这整个设置有几个重要的后果:




  • 你可以撕掉实例方法并获得绑定闭包。 o.foo 的结果会自动绑定到 o 。不需要自己绑定(但也没有办法绑定到一个不同的实例)。这是方式,在你的例子中, one.getMyId 工作。你实际上得到了以下闭包:()=>


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


  • var f = o.foo ; 意味着你总是得到一个新的关闭。这意味着你不能使用这个绑定封闭作为一个哈希表中的键。例如, register(o.foo)后跟 unregister(o.foo)很可能不工作,因为每个o.foo将不同。您可以通过尝试 print(o.foo == o.foo)很容易看到这一点。


  • 您不能将方法从一个对象传输到另一个对象。







查看您的示例:

  print('one $ {calling(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())}';

Inside callJustForThree

  callJustForThree(fn){
var three = new IDable(3);
three.fn();
}

three.fn()时,给定的参数 fn code>在最后一行Dart将会找到 three IDable )的类描述,然后在它中搜索 fn 因为它没有找到它,它会调用 noSuchMethod 回退。 fn 参数被忽略。



如果你想根据一些参数调用一个实例成员,你可以重写最后一个例子如下:

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

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


I used the below to see how dart calls methods passed in to other methods to see what context the passed in method would/can be called under.

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

So how does caller manager to call its argument fn without a context i.e. one.fn(), and why does callerJustForThree fail to call a passed in fn on an object which has that function defined for it?

解决方案

In Dart there is a difference between an instance-method, declared as part of a class, and other functions (like closures and static functions).

Instance methods are the only ones (except for constructors) that can access this. Conceptually they are part of the class description and not the object. That is, when you do a method call o.foo() Dart first extracts the class-type of o. Then it searches for foo in the class description (recursively going through the super classes, if necessary). Finally it applies the found method with this set to o.

In addition to being able to invoke methods on objects (o.foo()) it is also possible to get a bound closure: o.foo (without the parenthesis for the invocation). However, and this is crucial, this form is just syntactic sugar for (<args>) => o.foo(<args>). That is, this just creates a fresh closure that captures o and redirects calls to it to the instance method.

This whole setup has several important consequences:

  • You can tear off instance methods and get a bound closure. The result of o.foo is automatically bound to o. No need to bind it yourself (but also no way to bind it to a different instance). This is way, in your example, one.getMyId works. You are actually getting the following closure: () => one.getMyId() instead.

  • It is not possible to add or remove methods to objects. You would need to change the class description and this is something that is (intentionally) not supported.

  • var f = o.foo; implies that you get a fresh closure all the time. This means that you cannot use this bound closure as a key in a hashtable. For example, register(o.foo) followed by unregister(o.foo) will most likely not work, because each o.foo will be different. You can easily see this by trying print(o.foo == o.foo).

  • You cannot transfer methods from one object to another. However you try to access instance methods, they will always be bound.


Looking at your examples:

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

These lines are equivalent to:

 print('one ${caller(() => one.getMyId())}');
 print('two ${caller(() => two.getMyId())}');
 print('one ${callerJustForThree(() => one.getMyId())}';

Inside callerJustForThree:

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

The given argument fn is completely ignored. When doing three.fn() in the last line Dart will find the class description of three (which is IDable) and then search for fn in it. Since it doesn't find one it will call the noSuchMethod fallback. The fn argument is ignored.

If you want to call an instance member depending on some argument you could rewrite the last example as follows:

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

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

这篇关于dart方法调用上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆