基本Scala OOP问题-按引用传递?
我有点困惑于这个问题有多么愚蠢,我有一个严重的头脑空白,但我想我还是可以问一下 我有一个对象Foo,有几个字段。我想要一个方法,它可以根据作为参数传入的字段更改任何字段。像这样:基本Scala OOP问题-按引用传递?,oop,scala,Oop,Scala,我有点困惑于这个问题有多么愚蠢,我有一个严重的头脑空白,但我想我还是可以问一下 我有一个对象Foo,有几个字段。我想要一个方法,它可以根据作为参数传入的字段更改任何字段。像这样: class Foo { var x = 0 var y = 0 } class Bar { def changeFooField(field : Int) = { field = 1 } } 我可以不这样使用它吗 changeFooField(foo.
class Foo {
var x = 0
var y = 0
}
class Bar {
def changeFooField(field : Int) = {
field = 1
}
}
我可以不这样使用它吗
changeFooField(foo.x)
如果没有,我如何才能做到这一点?不,您不能。您需要将字段值包含到对象中:
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"
您想要的东西在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
一个常见的习惯用法是传递一个显式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=\ucode>是一个简单的临时闭包,允许对foo.x
进行写访问。无需将此setter API添加到Foo
本身
因此,事实证明,setter方法(foo.x=
–或者更确切地说,foo.x_=
)作为参数传递,与传递任何其他方法一样。您必须记住,Scala中的val
和var
实际上并不指定变量,而是创建方法,然后使用这些方法访问真实(隐藏)变量。(val
只创建一个getter方法,而var
当然同时创建getter和setter)。与上述所有答案相反,在Scala中,这实际上是完全可行的,无需编写任何特殊的包装器类
首先,您需要知道,对于任何非私有类var,例如原始问题中使用的类,Scala会自动生成getter和setter。因此,如果我们有一个名为“color”的var,Scala会自动创建一个名为“color”的getter和一个名为“color”的setter
接下来,您需要知道Scala允许您通过对任何方法调用特殊的“\u1”方法来获取对该方法的引用(这需要在其前面留出一个空格以消除歧义)
最后,将这些事实放在一起,您可以轻松获得对任何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
好的,谢谢。是的,我认为如果不创建一个新的对象来包装这个字段,这是不可能的。@Dominic基本的问题,没有明确提到,就是Int
s是不可变的。如果您的字段类型是可变的,如上面的示例所示,那么很容易用+1来代替定义设置字段
,我可以只应用xSetter
,比如f.xSetter(1)
。正确的?要达到同样的效果?@Nishant但是在这种情况下你也可以做f.x=1
。@Debilski哦,对了。:)所以我不知道为什么它是间接的?我的意思是,在斯卡拉有这样的模式吗?啊,没关系。通过引用传递是OP想要解释的。它是间接完成的,因为您不能在Scala中传递var
字段本身。因此,如果希望在其他方法中进行更改,则必须传递类本身或var
的特定setter。