Основной вопрос Scala ООП - перейдите по ссылке?
Я немного озадачен тем, насколько глупой эта проблема, и у меня серьезный ум, но я думал, что все равно могу спросить.
У меня есть объект Foo с несколькими полями. Я хочу метод, который может изменять любое из его полей, в зависимости от того, какой из них передается в качестве параметра. Например:
class Foo {
var x = 0
var y = 0
}
class Bar {
def changeFooField(field : Int) = {
field = 1
}
}
Могу ли я использовать его так?:
changeFooField(foo.x)
Если нет, как это сделать?
Ответы
Ответ 1
Нет, вы не можете. Вам нужно приложить значение поля к объекту:
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
Общей идиомой является передача явного метода 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 = _)
- это простое ad-hoc-замыкание, которое позволяет писать доступ к foo.x
. Нет необходимости добавлять этот API-интерфейс для установки в Foo
.
Итак, как выясняется, метод setter (foo.x=
- или, скорее, foo.x_=
) передается как аргумент точно так же, как передается любой другой метод. Вы должны помнить, что val
и var
в Scala фактически не указывают переменные, а создают методы, которые затем используются для доступа к реальным (скрытым) переменным. (val
создает только метод getter, тогда как var
, конечно, создает как getter, так и setter).
Ответ 3
В отличие от всех вышеперечисленных ответов это на самом деле вполне выполнимо в Scala без написания каких-либо специальных классов-оболочек.
Сначала вам нужно знать, что для любого непартийного класса var, такого как те, которые используются в исходном вопросе, Scala автоматически генерирует геттеры и сеттеры. Так что, если у нас есть var, называемый "color", Scala автоматически создает геттер, именуемый "цвет", и сеттер, называемый "color _ =".
Далее вам нужно знать, что 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
Ответ 4
То, чего вы хотите, не существует в 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 = [email protected]
scala> f.x
res0: Int = 0
scala> setField(f.xSetter)
scala> f.x
res3: Int = 1