为什么dart在引用方法时会创建闭包?

时间:2013-05-09 09:09:00

标签: closures dart

void main() {
  A one = new A(1);
  A two = new A(2);

  var fnRef = one.getMyId;        //A closure created here
  var anotherFnRef = two.getMyId; //Another closure created here
}

class A{
  int _id;
  A(this._id);
  int getMyId(){
    return _id;
  }
}

根据dart language tour页面,这样的引用方法每次都会创建一个新的闭包。有谁知道为什么这样做?我可以理解在定义方法体时创建闭包,因为我们可以在方法体内的外部作用域中使用变量,但是当引用上面的方法时,为什么创建闭包,因为方法体不会改变所以它不能使用该范围内可用的任何变量都可以吗?我在一个previous问题中注意到我要求这样的引用方法将它们有效地绑定到它们被引用的对象上。所以在上面的例子中,如果我们调用fnRef()它的行为就像one.getMyId()那么闭包只用于绑定调用上下文吗? ......我很困惑:S

更新

回应Ladicek。这是否意味着:

void main(){
    var fnRef = useLotsOfMemory();
    //did the closure created in the return statement close on just 'aVeryLargeObj'
    //or did it close on all of the 'veryLargeObjects' thus keeping them all in memory 
    //at this point where they aren't needed
}

useLotsOfMemory(){
    //create lots of 'veryLarge' objects
    return aVeryLargeObj.doStuff;
}

2 个答案:

答案 0 :(得分:4)

Ladicek是对的:以getter方式访问方法会自动绑定方法。

回应更新的问题:

没有。它不应该保持范围。绑定闭包通常实现为调用相同名称的getter:

class A{
  int _id;
  A(this._id);
  int getMyId() => _id;

  // The implicit getter for getMyId. This is not valid
  // code but explains how dart2js implements it. The VM has
  // probably a similar mechanism.
  Function get getMyId { return () => this.getMyId(); }
}

以这种方式实现时,您将无法捕获useLotsOfMemory函数中存在的任何变量。


即使它真的是在useLotsOfMemory函数内部分配闭包,也不清楚它是否保留了大量内存。

Dart没有指定创建闭包时捕获多少(或多少)。显然,它至少需要捕获自身的自由变量。这是最低限度。因此问题是:“它捕获了多少”?

普遍的共识似乎是捕获某些闭包中的所有可用变量。一些闭包捕获的所有局部变量都被移动到一个上下文对象中,每个创建的闭包只会存储一个到该对象的链接。

示例:

foo() {
  var x = new List(1000);
  var y = new List(100);
  var z = new List(10);
  var f = () => y;  // y is free here.
  // The variables y and z are free in some closure.
  // The returned closure will keep both alive.
  // The local x will be garbage collected.
  return () => z;  // z is free here.
}

我见过的Scheme实现只捕获了自己的自由变量(将上下文对象拆分成独立的部分),所以可能性较小。但是在达特这不是一个要求,我不会依赖它。为了安全起见,我总是假设所有捕获的变量(独立于谁捕获它们)都保持活着。 我还假设绑定闭包的实现类似于我在上面显示的内容,并且它们保持严格的内存最小值。

答案 1 :(得分:2)

这是完全正确的 - 闭包捕获将调用该方法的对象。

相关问题