基本的 Scala OOP 问题 - 通过引用传递?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6896118/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Basic Scala OOP question - pass by reference?
提问by Dominic Bou-Samra
I'm a little stumped at how silly this problem is and have a serious mindblank, but I thought I might ask anyway.
我对这个问题有多愚蠢感到有些困惑,并且有严重的脑空白,但我想我还是会问。
I have an object Foo, with several fields. I want a method that can change any of its fields depending on which one is passed in as a parameter. Like so:
我有一个对象 Foo,有几个字段。我想要一种可以根据作为参数传入的字段来更改其任何字段的方法。像这样:
class Foo {
var x = 0
var y = 0
}
class Bar {
def changeFooField(field : Int) = {
field = 1
}
}
Can I not use it like so?:
我不能像这样使用它吗?:
changeFooField(foo.x)
If not, how do I accomplish this?
如果没有,我该如何实现?
采纳答案by paradigmatic
No you cannot. You'll need to enclose the field value into an object:
你不能。您需要将字段值包含在一个对象中:
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"
回答by Debilski
A common idiom is to pass an explicit setter method which takes care of changing the value.
一个常见的习惯用法是传递一个显式的 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 = _)is a simple ad-hoc closure which allows write access to foo.x. There is no need in adding this setter API to Fooitself.
(foo.x = _)是一个简单的临时闭包,它允许对foo.x. 无需向Foo自身添加此 setter API 。
So, as it turns out, the setter method (foo.x=– or rather foo.x_=) is passed as an argument exactly as any other method is passed. You'll have to remember that valand varin Scala don't actually specify variables but create the methods which are then used to access the real (hidden) variables. (valonly creates a getter method, whereas varof course creates both getter and setter).
因此,事实证明,setter 方法(foo.x=– 或更确切地说foo.x_=)作为参数传递,与传递任何其他方法完全一样。你必须记住,val和varScala中实际上不指定变量,但创建然后用于访问真正的(隐藏)的变量的方法。(val只创建一个 getter 方法,而var当然创建 getter 和 setter)。
回答by Magnus
Contrary to all the answers above, this in fact is quite doable in Scala without writing any special wrapper classes.
与上面的所有答案相反,这实际上在 Scala 中是完全可行的,而无需编写任何特殊的包装类。
First you need to know that for any non-private class var, such as the ones used in the original question, Scala automatically generates getters and setters. So if we have a var called "color", Scala automatically creates a getter eponymously called "color" and a setter called "color_=".
首先,您需要知道对于任何非私有类 var,例如原始问题中使用的那些,Scala 会自动生成 getter 和 setter。因此,如果我们有一个名为“color”的变量,Scala 会自动创建一个名为“color”的 getter 和一个名为“color_=”的 setter。
Next you need to know that Scala lets you obtain a reference to any method by calling the special "_" method on it (which requires a space before it for disambiguation).
接下来,您需要知道 Scala 允许您通过调用特殊的“_”方法来获取对任何方法的引用(它需要在它之前有一个空格以消除歧义)。
Finally putting these facts together, you can easily get a type-safe reference to any var's getter/setter and use that reference to dynamically set/get that var's value:
最后将这些事实放在一起,您可以轻松获得对任何 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
回答by Kim Stebel
What you want doesn't exist in Scala/Java. The closest thing would be passing around a setter function.
你想要的东西在 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

