使用lambda中的class字段作为参数Scala

时间:2017-04-09 00:22:57

标签: scala lambda

我正在尝试创建一个构造函数,其中一个方法可以传递。看我的代码:

class Foo(fooMethod: () => Unit, var x: Int, var y: Int) {
  def foo() = fooMethod()
}

class Bar(x: Int) extends Foo(() => {
  var test1 = x
  var test2 = y
  println(x + ", " + y)
}, x, 50)


class FieldDemo {
  def main(args: Array[String]): Unit = {
    val bar = new Bar(40)
    bar.foo()
  }
}

此示例中的val test1 = x确实有效,因为它是Bar构造函数的参数,但val test2 = y不起作用,即使Bar扩展{{1} }和Foo有一个名为Foo的字段。

所以我的问题是:为什么你无法访问y

中函数内y类变量的Foo

修改

在阅读答案时,请查看Matheusz Kubuszok和http://ideone.com/9yMpvw vs http://ideone.com/0fDxXe的第一条评论。第二个链接是第一个链接中的代码也应该失败的原因。我想像这样的边缘情况检测会使编译器变得更复杂,所以我现在确实理解为什么他们选择不允许它。

1 个答案:

答案 0 :(得分:3)

基本上你的代码等同于:

val barFun(x: Int) = () => {
  var test1 = x
  var test2 = y
  println(x + ", " + y)
}

class Bar(x: Int) extends Foo(barFun(x), x, 50)

当你创建lambda时,它只看到传递给构造函数的参数 - 它是在构造函数的范围内创建的,因此它可以访问作为闭包传递给它的变量。 可以访问Foo类,因为它不是它的封闭类。如果您执行以下操作,可以查看:

class Bar(z: Int) extends Foo(() => {
  var test1 = x
  var test2 = y
  println(x + ", " + y)
}, z, 50)

您会看到lambda无法访问xy。我在菊石试验的其他测试表明:

class Bar(z: Int) extends Foo(() => {
  var test1 = Foo.this.x
  var test2 = Bar.this.y
}, z, 50)
cmd1.sc:2: Foo is not an enclosing class
  var test1 = Foo.this.x
              ^
cmd1.sc:3: Bar is not an enclosing class
  var test2 = Bar.this.y
              ^
Compilation Failed

事实上,这是一种感觉。在您创建lambda的那一刻,类尚未初始化。如果你在类初始化期间做的任何事情都可以访问所有那些未初始化的var,那么事情可能会变得讨厌。