基本的Scala OOP问题 - 通过引用传递?

时间:2011-08-01 08:53:41

标签: oop scala

我有点难以理解这个问题是多么愚蠢而且有严重的思维空白,但我想我还是会问。

我有一个对象Foo,有几个字段。我想要一个可以更改其任何字段的方法,具体取决于作为参数传入的字段。像这样:

class Foo {
    var x = 0
    var y = 0
}

class Bar {
    def changeFooField(field : Int) = {
        field = 1        
    }
}

我可以不这样使用吗?:

changeFooField(foo.x)

如果没有,我该如何做到这一点?

4 个答案:

答案 0 :(得分:16)

一个常见的习惯用法是传递一个显式的setter方法,该方法负责改变值。

class Foo {
  var x = 0
  var y = 0
}

class Bar {
  def changeFooField(setter: (Int) => Unit) = {
    setter(1)
  }
}

val foo = new Foo
val bar = new Bar
bar.changeFooField(foo.x = _) // or equivalent: bar.changeFooField((i: Int) => foo.x = i)

assert(foo.x == 1)

(foo.x = _)是一个简单的临时闭包,允许对foo.x进行写访问。无需将此setter API添加到Foo本身。

因此,事实证明,setter方法(foo.x= - 或者更确切地说foo.x_=)作为参数传递,与传递任何其他方法完全相同。您必须记住,Scala中的valvar实际上并未指定变量,而是创建用于访问实际(隐藏)变量的方法。 (val只创建一个getter方法,而var当然会创建getter和setter)。

答案 1 :(得分:13)

不,你不能。您需要将字段值括在一个对象中:

class Field[T]( var value: T )

class Foo {
  val x = new Field(0)
  val y = new Field(0)
}

class Bar {
  def changeFooField( field: Field[Int] ) {
    field.value = 1
  } 
}

val f = new Foo
(new Bar).changeFooField( f.x )
println( f.x.value + " / " + f.y.value ) // prints "1 / 0"

答案 2 :(得分:7)

与上面的所有答案相反,这实际上在Scala中非常可行而没有编写任何特殊的包装类。

首先,您需要知道对于任何非私有类var,例如原始问题中使用的那些,Scala会自动生成getter和setter。因此,如果我们有一个名为“color”的var,Scala会自动创建一个名为“color”的getter和一个名为“color _ =”的setter。

接下来,您需要知道Scala允许您通过在其上调用特殊的“_”方法来获取对任何方法的引用(在消除歧义之前需要一个空格)。

最后将这些事实放在一起,您可以轻松获得任何var的getter / setter的类型安全引用,并使用该引用动态设置/获取该var的值:

class Foo {
    var x = 0
}

object Foo {
    def setField[T](setter: T => Unit, value: T) {setter(value)}
    def getField[T](getter: () => T ) = {getter()}
}

val f = new Foo
val xsetter = f.x_= _
val xgetter = f.x _

Foo.setField(xsetter, 3)
println(f.x) //prints 3
println(Foo.getField(xgetter)) //prints 3

答案 3 :(得分:2)

Scala / Java中不存在您想要的内容。最接近的是传递一个setter函数。

scala> class Foo {
     | var x = 0
     | var y = 0
     | val xSetter = (i:Int) => x = i
     | val ySetter = (i:Int) => y = i
     | }
defined class Foo

scala> def setField(setter:Int=>Unit) = setter(1)
setField: (setter: (Int) => Unit)Unit

scala> val f = new Foo
f: Foo = Foo@eb203b

scala> f.x
res0: Int = 0

scala> setField(f.xSetter)

scala> f.x
res3: Int = 1