Pertanyaan Pertanyaan Basic Basic OOP - lewat referensi?


Saya sedikit bingung dengan betapa bodohnya masalah ini dan memiliki pikiran yang serius, tetapi saya pikir saya mungkin akan bertanya.

Saya memiliki objek Foo, dengan beberapa bidang. Saya ingin metode yang dapat mengubah bidangnya tergantung pada mana yang dilewatkan sebagai parameter. Seperti ini:

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

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

Bisakah saya tidak menggunakannya seperti itu ?:

changeFooField(foo.x)

Jika tidak, bagaimana saya mencapai ini?


18
2017-08-01 08:53


asal


Jawaban:


Tidak Anda tidak bisa. Anda harus menyertakan nilai bidang ke dalam objek:

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"

13
2017-08-01 09:08



Ungkapan yang umum adalah menyampaikan metode penyetel eksplisit yang menangani perubahan nilai.

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 = _) adalah penutupan ad-hoc sederhana yang memungkinkan akses tulis ke foo.x. Tidak perlu menambahkan API setter ini Foo diri.

Jadi, ternyata, metode setter (foo.x= - atau sebaiknya foo.x_=) dilewatkan sebagai argumen persis seperti metode lain yang dilewatkan. Anda harus mengingat itu val dan var di Scala tidak benar-benar menentukan variabel tetapi membuat metode yang kemudian digunakan untuk mengakses variabel nyata (tersembunyi). (val hanya menciptakan metode pengambil, sedangkan var tentu saja menciptakan pengambil dan penyetel).


16
2017-08-01 09:28



Bertentangan dengan semua jawaban di atas, ini sebenarnya cukup bisa dilakukan di Scala tanpa menulis kelas pembungkus khusus.

Pertama Anda perlu tahu bahwa untuk setiap var kelas non-swasta, seperti yang digunakan dalam pertanyaan asli, Scala secara otomatis menghasilkan getter dan setter. Jadi jika kita memiliki var yang disebut "warna", Scala secara otomatis membuat pengambil disebut secara eponim sebagai "warna" dan seorang penyetel bernama "color_ =".

Selanjutnya Anda perlu tahu bahwa Scala memungkinkan Anda memperoleh referensi ke metode apa pun dengan memanggil metode "_" khusus di atasnya (yang membutuhkan ruang sebelum disambiguasi).

Akhirnya menempatkan fakta-fakta ini bersama-sama, Anda dapat dengan mudah mendapatkan referensi jenis-aman untuk setiap pengambil / penyetel var dan menggunakan referensi tersebut untuk secara dinamis menetapkan / mendapatkan nilai var itu:

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

7
2018-03-20 23:54



Apa yang Anda inginkan tidak ada di Scala / Java. Hal yang paling dekat akan melewati fungsi 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

2
2017-08-01 09:16