Scala:清理构造函数参数

Pij*_*usn 2 parameters constructor garbage-collection scala

我只是在学习Scala,并担心清理构造函数参数.

在Java中,我有一个这样的类:

public class Example {
    private A a;
    private B b;

    private SelectorA aSelector;
    private SelectorB bSelector;

    public Example(SelectorA aSelector, SelectorB bSelector) {
        this.aSelector = Objects.requireNonNull(aSelector);
        this.bSelector = Objects.requireNonNull(bSelector);
    }

    public void start() {
        if (a == null) {
            a = aSelector.select();
            aSelector = null; // Removing reference.
        }

        if (b == null) {
            b = bSelector.select();
            bSelector = null; // Removing reference.
        }

        // Go on.
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,它更复杂,有参数和东西.这个类假设是一个长寿的类,我只是想确保它没有任何它不需要的引用.

我即将把这个类移植到Scala并创建了这样的类:

class Example(_aSelector: Selector[A], _bSelector: Selector[B]) {
    private lazy val _a = _aSelector() // Will _aSelector reference be cleared?
    private lazy val _b = _bSelector() // Will _bSelector reference be cleared?

    def start() = {
        // Use _a.
        // Use _b.
        // Go on.
    }
}
Run Code Online (Sandbox Code Playgroud)

再次,它会更复杂,但想法很清楚.那么,问题是:

Scala是否能够检测不再需要哪些构造函数参数(_aSelector以及_bSelector上面的示例中)?或者我是否必须明确清除参考?

_a
_aSelector = null
_b
_bSelector = null
Run Code Online (Sandbox Code Playgroud)

PS我明白GC是检测范围外引用的那个,但Scala编译器是定义变量范围的一个,因此它是一个定义行为.

sjr*_*jrd 6

使用lazy vals,您明确要求_a仅在第一次访问时进行初始化.这需要_aSelector在构造函数结束后保持引用,至少直到_a第一次访问.

然而 - 它让我感到惊讶 - 看起来scalac足够聪明,可以生成在成功初始化_aSelector之后归零的代码_a.

您可以通过以下方式验证scalac -Xprint:mixin:

Test.scala:

class Test(factory: () => Int) {
  lazy val x = factory()
}
Run Code Online (Sandbox Code Playgroud)

然后:

$ scalac -Xprint:mixin Test.scala
class Test extends Object {
  @volatile private[this] var bitmap$0: Boolean = false;
  private def x$lzycompute(): Int = {
    {
      Test.this.synchronized({
        if (Test.this.bitmap$0.unary_!())
          {
            Test.this.x = Test.this.factory.apply$mcI$sp();
            Test.this.bitmap$0 = true;
            ()
          };
        scala.runtime.BoxedUnit.UNIT
      });
      Test.this.factory = null // <-- LOOK HERE
    };
    Test.this.x
  };
  <paramaccessor> private[this] val factory: Function0 = _;
  lazy private[this] var x: Int = _;
  <stable> <accessor> lazy def x(): Int = if (Test.this.bitmap$0.unary_!())
    Test.this.x$lzycompute()
  else
    Test.this.x;
  def <init>(factory: Function0): Test = {
    Test.this.factory = factory;
    Test.super.<init>();
    ()
  }
};
Run Code Online (Sandbox Code Playgroud)

因此,一旦_a第一次访问并成功初始化,是的,_aSelector将发布引用,GC将能够回收它.