Подтвердить что ты не робот

Основной вопрос Scala ООП - перейдите по ссылке?

Я немного озадачен тем, насколько глупой эта проблема, и у меня серьезный ум, но я думал, что все равно могу спросить.

У меня есть объект Foo с несколькими полями. Я хочу метод, который может изменять любое из его полей, в зависимости от того, какой из них передается в качестве параметра. Например:

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

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

Могу ли я использовать его так?:

changeFooField(foo.x)

Если нет, как это сделать?

4b9b3361

Ответ 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