dart方法调用上下文 [英] dart method calling context
问题描述
我使用下面的例子来看看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 too
. 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 byunregister(o.foo)
will most likely not work, because each o.foo will be different. You can easily see this by tryingprint(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屋!