3
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 语言游览页面引用方法,这样的方法每次都会创建一个新的闭包。有谁知道它为什么这样做?我可以理解在定义方法体时创建闭包,因为我们可以在方法体的外部范围内使用变量,但是当只是引用像上面这样的方法时,为什么要创建闭包,因为方法体没有改变所以它不能使用该范围内可用的任何变量都可以吗?我注意到在一个问题中我问过像这样的引用方法有效地将它们绑定到它们被引用的对象。所以在上面的例子中,如果我们调用fnRef()它,它的行为会像one.getMyId()这样,闭包只是用于绑定调用上下文吗?...我很困惑:S

更新

回应拉迪切克。这是否意味着:

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;
}
4

2 回答 2

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 实现,因此可能性较小。但是在 Dart 中,这不是必需的,我不会依赖它。为了安全起见,我总是假设所有捕获的变量(与捕获它们的人无关)都保持活动状态。我还将假设绑定闭包的实现类似于我上面展示的内容,并且它们保持严格的最小内存活动。

于 2013-05-09T10:48:08.640 回答
2

完全正确——闭包捕获了将在其上调用方法的对象。

于 2013-05-09T09:33:35.203 回答