özel [bu] - özel


112

Scala'da nesne-özel değişken gibi bir özellik görüyorum. Çok zengin olmayan Java geçmişimden her şeyi kapatmayı (özel hale getirmeyi) ve gerekirse açmayı (erişim sağlama) öğrendim. Scala, daha da katı erişim değiştiricileri sunar. Her zaman varsayılan olarak kullanmalı mıyım? Ya da sadece, aynı sınıftaki nesneler için bile değişen alan değerini açıkça kısıtlamam gereken belirli durumlarda kullanmalı mıyım? Başka bir deyişle, nasıl seçim yapmalıyım

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

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

İkincisi daha katı ve hoşuma gidiyor ama her zaman mı yoksa sadece güçlü bir sebebim varsa mı kullanmalıyım?

REDAKTE: Anlıyorum gibi burada private[this] sadece bazı subcase ve yerine ise this"Paket, sınıf veya tekil nesne": Başka değiştiricileri kullanabilirsiniz. Bu yüzden bazı özel durumlar için bırakacağım.


Yanıtlar:


59

Herhangi bir değişiklik her iki şekilde de yalnızca bir sınıfa dokunacağı için bunun çok önemli olduğunu düşünmüyorum. En önemli nedeni tercih Yani privateüzerinde protectedüzerinde publicgeçerli değildir.

private[this]Performansın gerçekten önemli olduğu yerlerde kullanın (çünkü bu şekilde yöntemler yerine doğrudan alan erişimi elde edeceksiniz). Aksi takdirde, bir stil sadece yerleşmek insanlar neden anlamaya gerek kalmaz bu özelliktir privateve bu biridir private[this].


6
@ om-nom-nom Aslında söylenecek pek bir şey yok. JIT, privateyine de üretilen erişimci yöntemi çağrılarını satır içi yapmalıdır , bu nedenle etki sıfır veya en azından çok çok küçük olmalıdır.
Alexey Romanov

9
Bu yanıt yanıltıcıdır, asıl neden bildirim sitesi farklılığıdır (şu yanıta bakın: stackoverflow.com/a/9727849/445715 ).
Andrey Breslav

1
@AndreyBreslav Bunun olduğunu katılmıyorum sebep. Evet, böyle bir durum var ama cevabın dediği gibi oldukça nadir.
Alexey Romanov

3
Hmm. Marek Adamek'in aşağıdaki cevabı, özel yerine özel olanı seçmenin gerçek nedeni gibi görünüyor. Amaç, sınıfın tüm örneklerinin aksine, belirli bir örneğe erişimi sınırlamaktır.
Ram Rajamony

3
@AlexeyRomanov - soru "Her zaman varsayılan olarak kullanmalı mıyım?" Sanırım, aynı sınıfın başka bir örneğinden alana ihtiyacınız varsa özel [this] 'in kullanılamayacağını söyleyerek yanıtınızı geliştirebilirsiniz.
Ram Rajamony

130

private[this]Kod derlemek için gerekli olan bir durum var . Bunun varyans gösterimi ve değişebilir değişkenlerin etkileşimi ile ilgisi vardır. Şu (işe yaramaz) sınıfı düşünün:

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

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

Dolayısıyla bu sınıf, isteğe bağlı bir değeri tutacak, onu bir seçenek olarak döndürecek ve kullanıcının makeEmptydeğeri temizlemek için arama yapmasını sağlayacak şekilde tasarlanmıştır (dolayısıyla var). Belirtildiği gibi, bu noktayı göstermek dışında faydasızdır.

Bu kodu privateonun yerine ile derlemeyi denerseniz private[this], aşağıdaki hata mesajı ile başarısız olur:

hata: kovaryant türü T türü, değer değer_ = sınıf Tutucu [+ T] türünün Seçenek [T] türünde aykırı konumda ortaya çıkar (başlangıçDeğeri: Seçenek [T]) {

Bu hata, değerin ortak değişken türü T (+ T) üzerinde değiştirilebilir bir değişken olması nedeniyle oluşur ve bu, örneğe özel olarak işaretlenmedikçe normalde bir sorundur private[this]. Derleyicinin bu özel durumu ele almak için varyans kontrolünde özel bir kullanımı vardır.

Yani ezoterik ama tekrarlanması private[this]gereken bir durum var private.


1
Karışımda değişkenlik varken neden başarısız olduğunu anlayabiliyorum, ama neden hiçbir şey değiştirilebilir olmadığında aynı hatayı alıyorum ?
Matt Kantor

35

private var nameclass Dummy(ve arkadaşının object Dummy) herhangi bir yönteminden erişilebilir .

private[this] var namethisdiğer nesnelerden değil, yalnızca nesne yöntemlerinden erişilebilir class Dummy.


18

private [this] (korumalı [this] ile eşdeğerdir), "y" nin yalnızca aynı durumdaki yöntemler tarafından görülebileceği anlamına gelir. Örneğin, bir eşittir yönteminde ikinci bir örnekte y'ye başvuruda bulunamazsınız, yani "this.y == that.y", "that.y" üzerinde bir derleme hatası oluşturur. (kaynak)

böylece istediğiniz zaman özel [bunu] yapabilirsiniz, ancak başvurmanız gerekirse biraz sorun yaşayabilirsiniz


13
private[this]eşit değildir protected[this]. protected[this]alt sınıf örneklerinin üyeye erişmesine izin verir.
drexin

this.y == that.yNe özel ne de özel kullanarak yapabilirsiniz [bunu], az önce ikisini de denedim
lisak

12

Bu, scala 2.11.5 kullanılarak test edildi. Aşağıdaki kodu düşünün

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

bu java (1.8) kodu olarak derlenecek ve çalışacaktır

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

ancak '[this]' değiştiricisini kullanırsanız aşağıdaki kod derlenmez

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
  }
}

Bunun nedeni, ilk durumda 'x'in sınıf düzeyinde erişilebilir olması, ikinci durumda ise daha katı örnek düzeyinde olmasıdır. Bu, "x" e yalnızca ait olduğu örnekten erişilebileceği anlamına gelir. Yani 'this.x' iyi ama 'other.x' değil.

Erişim değiştiriciler hakkında daha fazla ayrıntı için "Scala'da Programlama: Kapsamlı Adım Adım Kılavuz" kitabının 13.5 bölümüne bakabilirsiniz.


1
Soru ne private[this]anlama geldiğini sormak değil . İlk cümleyi not edin.
Alexey Romanov

9

Kapsamı özel değiştiriciye ( özel [X] ) eklerken, etkin bir şekilde "en fazla" X gibi davranır; burada X, bazı çevreleyen paket, sınıf veya tekli nesneyi belirtir.

Örneğin, barın bir paket olduğu özel [bar] , paket çubuğuna ait her sınıfın her örneğinin değiştiricinin kısıtladığı üyeye erişebileceği anlamına gelir .

Özel durumda [bu] , üyenin yalnızca her durum için erişilebilir olduğu anlamına gelir. Bu, aşağıdaki örnekte daha net hale gelir:

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

Gördüğünüz gibi, ikinci Foo'da herhangi bir sorun yok çünkü herhangi bir örnek özel değere erişebilir. Ancak ilk Foo için bir hata vardır çünkü her bir örnek diğer örneklerin i'yi göremez.

Daha büyük bir kısıtlama getirdiği için özel [bunu] yazmak iyi bir uygulamadır.


6

Java gibi çoğu OOP programlama dilinde, özel alanlar / yöntemler, bu özel alanların / yöntemlerin sınıfın dışında erişilebilir olmadığı anlamına gelir. Bununla birlikte, aynı sınıftaki örnekler / nesneler, nesnelerin özel alanlarına atama operatörü veya kopya yapıcısı aracılığıyla erişebilir. Scala'da, özel [bu] nesneye özeldir, bu da aynı sınıftaki diğer nesnelerin özel [bu] üyelere erişememesini sağlar.

Misal

1. Özel olmadan [bu]

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. Özel kullanım [bu]

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

  }
}

Dolayısıyla özel [bu], _password alanına yalnızca bununla erişilebilmesini sağlar.


Bu açık ara en net ve daha objektif cevaptır.
Lucas Lima

2

Alexey Romanov'un bahsettiği performans konusunu detaylandırmak için, işte benim tahminlerimden bazıları. "Scala'da Programlama: Kapsamlı Adım Adım Kılavuz, 2. Baskı" Bölüm 18.2 kitabından alıntılar:

Scala'da, bazı nesnelerin özel olmayan üyesi olan her değişken, örtülü olarak bir alıcı ve onunla bir ayarlayıcı yöntemi tanımlar.

Test etmek için, bu kod derleme hatasına neden olacaktır:

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

Scala bundan şikayet ediyor error: ambiguous reference to overloaded definition. Geçersiz kılma anahtar sözcüğünü eklemek data_=, yöntemin derleyici tarafından oluşturulduğunu kanıtlamamalıdır. privateDeğişkene anahtar kelime eklemek datayine de bu derleme hatasına neden olacaktır. Ancak, aşağıdaki kod iyi derler:

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

Dolayısıyla, private[this]scala'nın alıcı ve ayarlayıcı yöntemlerini oluşturmasını engelleyeceğini tahmin ediyorum . Bu nedenle, böyle bir değişkene erişim, alıcı ve ayarlayıcı yönteminin çağrılmasının ek yükünden tasarruf sağlayacaktır.


1

Her zaman varsayılan olarak kullanmalı mıyım? Ya da sadece, aynı sınıftaki nesneler için bile değişen alan değerini açıkça kısıtlamam gereken belirli durumlarda kullanmalı mıyım? Başka bir deyişle, nasıl seçim yapmalıyım

private[this]Değişkeni senkronize etmeyi planlıyorsanız kullanmak daha iyidir .

Spark ekibinin scala stil kılavuzundan güzel bir örnek :

// 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 }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.