pribadi [ini] vs pribadi

112

Di Scala saya melihat fitur seperti variabel objek-pribadi. Dari latar belakang Java saya yang tidak terlalu kaya, saya belajar untuk menutup semuanya (membuatnya pribadi) dan membuka (menyediakan pengakses) jika perlu. Scala memperkenalkan pengubah akses yang lebih ketat. Haruskah saya selalu menggunakannya secara default? Atau haruskah saya menggunakannya hanya dalam beberapa kasus tertentu di mana saya perlu secara eksplisit membatasi perubahan nilai bidang bahkan untuk objek dari kelas yang sama? Dengan kata lain, bagaimana saya harus memilih di antara keduanya

class Dummy {
    private var name = "default name"
}

class Dummy {
    private[this] var name = "default name"
}

Yang kedua lebih ketat dan saya menyukainya tetapi haruskah saya selalu menggunakannya atau hanya jika saya memiliki alasan yang kuat?

DIEDIT: Seperti yang saya lihat di sini private[this] hanya beberapa sub-huruf dan alih-alih thissaya dapat menggunakan pengubah lain: "paket, kelas atau objek tunggal". Jadi saya akan meninggalkannya untuk beberapa kasus khusus.

Soterik
sumber

Jawaban:

59

Saya tidak berpikir itu terlalu penting, karena perubahan apa pun hanya akan menyentuh satu kelas. Jadi alasan yang paling penting untuk memilih privatelebih protectedlebih publictidak berlaku.

Gunakan di private[this]mana kinerja benar-benar penting (karena Anda akan mendapatkan akses lapangan langsung daripada metode dengan cara ini). Jika tidak, hanya menetap di satu gaya sehingga orang tidak perlu mencari tahu mengapa ini properti privatedan yang satu adalah private[this].

Alexey Romanov
sumber
6
@ om-nom-nom Sebenarnya, tidak banyak yang bisa diceritakan. JIT harus menyebariskan panggilan metode pengakses yang dihasilkan private, jadi dampaknya harus nol atau setidaknya sangat kecil.
Alexey Romanov
9
Jawaban ini menyesatkan, alasan sebenarnya adalah perbedaan situs deklarasi (lihat jawaban ini: stackoverflow.com/a/9727849/445715 ).
Andrey Breslav
1
@AndreyBreslav Saya tidak setuju bahwa ini adalah yang alasan. Ya, kasus seperti itu ada tetapi seperti yang dikatakan jawabannya, itu sangat jarang.
Alexey Romanov
3
Hmm. Jawaban Marek Adamek di bawah ini sepertinya menjadi alasan sebenarnya untuk memilih private [ini] daripada private. Tujuannya adalah untuk membatasi akses ke instance tertentu, sebagai kebalikan dari semua instance kelas.
Ram Rajamony
3
@AlexeyRomanov - pertanyaannya menanyakan "Haruskah saya selalu menggunakannya secara default?". Saya pikir Anda dapat meningkatkan jawaban Anda dengan mengatakan bahwa private [ini] tidak dapat digunakan jika Anda membutuhkan field dari instance lain dari kelas yang sama.
Ram Rajamony
130

Ada kasus di mana private[this]diperlukan untuk membuat kompilasi kode. Ini ada hubungannya dengan interaksi notasi varians dan variabel yang bisa berubah. Pertimbangkan kelas (tidak berguna) berikut:

class Holder[+T] (initialValue: Option[T]) {
    // without [this] it will not compile
    private[this] var value = initialValue

    def getValue = value
    def makeEmpty { value = None }
}

Jadi kelas ini dirancang untuk menampung nilai opsional, mengembalikannya sebagai opsi dan memungkinkan pengguna untuk memanggil makeEmptyuntuk menghapus nilai (karena itu var). Seperti yang dinyatakan, ini tidak berguna kecuali untuk menunjukkan maksudnya.

Jika Anda mencoba mengompilasi kode ini dengan privatealih - alih private[this]itu akan gagal dengan pesan kesalahan berikut:

error: tipe kovarian T terjadi pada posisi kontravarian dalam tipe Option [T] dengan nilai value_ = class Holder [+ T] (initialValue: Option [T]) {

Kesalahan ini terjadi karena nilai adalah variabel yang dapat berubah pada tipe kovarian T (+ T) yang biasanya menjadi masalah kecuali ditandai sebagai pribadi untuk instance dengan private[this]. Kompilator memiliki penanganan khusus dalam pemeriksaan variansnya untuk menangani kasus khusus ini.

Jadi itu esoterik tetapi ada kasus di mana private[this]harus diselesaikan private.

denis phillips
sumber
1
Saya dapat melihat mengapa gagal ketika mutabilitas ada dalam campuran, tetapi mengapa saya mendapatkan kesalahan yang sama ketika tidak ada yang bisa berubah ?
Matt Kantor
35

private var namedapat diakses dari metode apa pun class Dummy(dan pendampingnya object Dummy).

private[this] var namedapat diakses dari metode thisobjek saja, bukan dari objek lain class Dummy.

comonad
sumber
18

private [ini] (setara dengan dilindungi [ini]) berarti bahwa "y" hanya terlihat oleh metode dalam instance yang sama. Misalnya, Anda tidak dapat mereferensikan y pada instance kedua dalam metode yang sama, yaitu, "this.y == that.y" akan menghasilkan kesalahan kompilasi pada "that.y". (sumber)

sehingga Anda dapat melakukan [ini] pribadi setiap kali Anda mau tetapi Anda dapat memiliki beberapa masalah jika Anda perlu merujuknya

Pben
sumber
13
private[this]tidak sama dengan protected[this]. protected[this]memungkinkan instance subclass mengakses anggota.
drexin
Anda tidak dapat this.y == that.ymenggunakan baik pribadi maupun pribadi [ini], saya baru mencoba keduanya
lisak
12

Ini diuji menggunakan skala 2.11.5. Perhatikan kode di bawah ini

class C(private val x: Int) {
  override def equals(obj: Any) = obj match {
    case other: C => x == other.x
    case _ => false
  }
}

println(new C(5) == new C(5)) //true
println(new C(5) == new C(4)) //false

itu akan mengkompilasi dan bekerja sebagai kode java (1.8) ini

class C {
    private int x;

    public C(int x) {
        this.x = x;
    }

    public boolean equals(Object obj) {
        if (obj instanceof C) {
            return ((C) obj).x == x;
        }
        else {
            return false;
        }
    }
}

System.out.println(new C(5).equals(new C(5))); //true
System.out.println(new C(5).equals(new C(4))); //false

namun jika Anda menggunakan pengubah '[this]', kode di bawah ini tidak dapat dikompilasi

class C(private[this] val x: Int) {
  override def equals(obj: Any) = obj match {
    case other: C => this.x == other.x //problem is here
    case _ => false
  }
}

Ini karena dalam kasus pertama 'x' dapat diakses pada level kelas, sedangkan dalam kasus kedua adalah level instance yang lebih ketat. Ini berarti bahwa 'x' hanya dapat diakses dari instance yang dimilikinya. Jadi 'this.x' baik-baik saja tetapi 'other.x' tidak.

Anda dapat merujuk ke bagian 13.5 dari buku "Pemrograman dalam Skala: Panduan Langkah-demi-Langkah Komprehensif" untuk detail lebih lanjut tentang pengubah akses.

Marek Adamek
sumber
1
Pertanyaannya bukanlah menanyakan apa private[this]artinya. Perhatikan kalimat pertama.
Alexey Romanov
9

Saat menambahkan cakupan ke pengubah privat ( private [X] ), ia secara efektif berperilaku sebagai "hingga" X, di mana X menunjuk beberapa paket, kelas, atau objek tunggal yang melingkupi.

Misalnya, private [bar] , di mana bar adalah sebuah paket berarti bahwa setiap instance dari setiap kelas yang termasuk dalam bilah paket dapat mengakses anggota mana pun yang dibatasi oleh pengubah.

Dalam kasus pribadi [ini] , itu berarti bahwa anggota hanya dapat diakses untuk setiap contoh. Ini menjadi lebih jelas dalam contoh berikut:

class Foo(foo:Foo){  
   private[this] val i = 2
   println(this.i + foo.i)
}

>>error: value i is not a member of Foo

class Foo(foo:Foo){  
    private val i = 2
    println(this.i + foo.i)
}

>>defined class Foo

Seperti yang Anda lihat, Foo kedua tidak memiliki masalah karena setiap instance dapat mengakses private val i. Namun untuk Foo pertama, ada kesalahan karena setiap instance tidak dapat melihat instance lain i.

Merupakan praktik yang baik untuk menulis pribadi [ini] karena menerapkan batasan yang lebih besar.

Humoyun Ahmad
sumber
6

Di sebagian besar bahasa pemrograman OOP seperti java, bidang / metode pribadi berarti bahwa bidang / metode pribadi ini tidak dapat diakses di luar kelas. Namun, instance / objek dari kelas yang sama dapat memiliki akses ke bidang privat objek menggunakan operator penugasan atau dengan cara menyalin konstruktor. Di Scala, private [this] adalah objek private, yang memastikan bahwa objek lain dari kelas yang sama tidak dapat mengakses anggota private [this].

Contoh

1. Tanpa pribadi [ini]

object ObjectPrivateDemo {

  def main(args: Array[String]) {
    var real = new User("realUserName", "realPassword")
    var guest = new User("dummyUserName", "dummyPassword")
    real.displayUser(guest)

  }
}

class User(val username:String,val password:String) {
  private var _username=username
  private var _password=password



  def displayUser(guest:User){

         println(" guest username="+guest._username+" guest password="+guest._password)
       guest._username= this._username
    guest._password=  this._password
       println(" guest username="+guest._username+" guest password="+guest._password)


  }
}

2. Menggunakan pribadi [ini]

class User(val username: String, val password: String) {
  private var _username = username
  private[this] var _password = password



  def displayUser(guest: User) {

    println(this._username)
    println(this._password)

    guest._username = this._username
    // for guest._password it will give this :error  value _password is not member of class User
    guest._password = this._password

  }
}

Karenanya private [this] memastikan bahwa field _password hanya dapat diakses dengan ini.

rafiquenazir.dll
sumber
Sejauh ini, ini adalah jawaban yang paling jelas dan lebih obyektif.
Lucas Lima
2

Untuk menguraikan masalah kinerja yang disebutkan Alexey Romanov, berikut beberapa tebakan saya. Kutipan dari buku "Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition" Bagian 18.2:

Di Scala, setiap var yang merupakan anggota non-privat dari beberapa objek secara implisit mendefinisikan metode pengambil dan penyetel dengannya.

Untuk mengujinya, kode ini akan menyebabkan kesalahan kompilasi:

class PrivateTest{
  var data: Int = 0
  def data_=(x : Int){
    require(x > 0)
    data = x
  }
}

Scala mengeluh tentang error: ambiguous reference to overloaded definition. Menambahkan kata kunci override ke data_=tidak akan membantu harus membuktikan bahwa metode tersebut dihasilkan oleh compiler. Menambahkan privatekata kunci ke variabel datamasih akan menyebabkan kesalahan kompilasi ini. Namun, kode berikut dapat dikompilasi dengan baik:

class PrivateTest{
  private[this] var data: Int = 0
  def data_=(x : Int){
    require(x > 0)
    data = x
  }
}

Jadi, saya kira private[this]akan mencegah scala menghasilkan metode pengambil dan penyetel. Dengan demikian, mengakses variabel tersebut akan menghemat biaya pemanggilan metode pengambil dan penyetel.

DXDXY
sumber
1

Haruskah saya selalu menggunakannya secara default? Atau haruskah saya menggunakannya hanya dalam beberapa kasus tertentu di mana saya perlu secara eksplisit membatasi perubahan nilai bidang bahkan untuk objek dari kelas yang sama? Dengan kata lain, bagaimana saya harus memilih di antara keduanya

Lebih baik digunakan private[this]jika Anda berencana untuk menyinkronkan variabel.

Berikut contoh bagus dari panduan gaya skala tim Spark :

// The following is still unsafe.
class Foo {
  private var count: Int = 0
  def inc(): Unit = synchronized { count += 1 }
}

// The following is safe.
class Foo {
  private[this] var count: Int = 0
  def inc(): Unit = synchronized { count += 1 }
}
Andriy Kuba
sumber