частный [это] против частного



в Scala я вижу такую функцию, как object-private variable. Из моего не очень богатого Java-фона я научился закрывать все (делать его частным) и открывать (предоставлять доступы), если это необходимо. Scala вводит еще более строгий модификатор доступа. Должен ли я всегда использовать его по умолчанию? Или я должен использовать его только в некоторых конкретных случаях, когда мне нужно явно ограничить изменение значения поля даже для объектов одного класса? Другими словами, как я должен выбирать между



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

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


В второй-более строгий, и мне это нравится, но я должен всегда использовать или только если у меня есть веская причина?



отредактировано: как я вижу здесьprivate[this] просто некоторые ней и вместо this Я могу использовать другие модификаторы: "пакет, класс или объект-синглтон". Так что я оставлю это для какого-нибудь особого случая.

485   9  

9 ответов:

Я не думаю, что это имеет слишком большое значение, так как любые изменения будут касаться только одного класса в любом случае. Так что самая главная причина предпочесть private over protected over public не относится.

использовать private[this] где производительность действительно имеет значение (так как вы получите прямой доступ к полям вместо методов этот способ). В противном случае, просто остановитесь на одном стиле, чтобы людям не нужно было выяснять, почему этой недвижимость private и это один private[this].

есть случай, когда private[this] требуется для компиляции кода. Это связано с взаимодействием дисперсионной нотации и изменяемых переменных. Рассмотрим следующий (бесполезный) класс:

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

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

таким образом, этот класс предназначен для хранения необязательного значения, возврата его в качестве опции и позволяет пользователю вызывать makeEmpty чтобы очистить значение (следовательно, var). Как уже говорилось, это бесполезно, за исключением демонстрации точки.

если вы попытаетесь скомпилировать этот код с private вместо private[this] он завершится со следующим сообщением об ошибке:

ошибка: ковариантный тип T возникает в контравариантной позиции в типе Option[T] значения value_= держатель класса[+T] (initialValue: Option[T]) {

эта ошибка возникает из-за того, что value является изменяемой переменной ковариантного типа T (+T), которая обычно является проблемой, если не помечена как частная для экземпляра с private[this]. Компилятор имеет специальную обработку в проверке отклонений разберитесь с этим особым случаем.

так что это эзотерично, но есть случай, когда private[this] требуется private.

private var name доступно из любого метода class Dummy (и ее спутником object Dummy).

private[this] var name доступно из методов this только объект, а не из других объектов class Dummy.

private[this] (эквивалентно protected[this]) означает, что "y" является видимый только для методов в том же экземпляре. Например, вы могли бы не ссылаться y на второй экземпляр в методе equals, т. е., "этот.г ==, что.y "будет генерировать ошибку компиляции на" это.год." (источник)

Так что вы можете сделать частный[это] каждый раз, когда вы хотите, но вы можете иметь некоторые проблемы, если вам нужно обратиться к нему

Это было проверено с помощью scala 2.11.5. Рассмотрим код ниже

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

он будет компилироваться и работать как этот код java (1.8)

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

однако если вы используете модификатор '[this]', приведенный ниже код не будет компилироваться

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

это потому, что в первом случае 'x' доступен на уровне класса, тогда как во втором случае это более строгий уровень экземпляра. Это означает, что 'x' может быть доступен только из экземпляра, к которому он принадлежит. Так вот.х-это хорошо, но - другие.х-нет.

вы можете обратиться к разделу 13.5 книги "программирование в Scala: полное пошаговое руководство" для получения более подробной информации о модификаторах доступа.

при добавлении области в частная модификатор ( private[X]), Он эффективно ведет себя как "до" X, где X обозначает некоторый заключительный пакет, класс или одноэлементный объект.

например, private [bar], где бар - это пакет означает, что каждый экземпляр каждого класса, принадлежащих к пакет бар может получить доступ к любому члену модификатор ограничивает.

в случае частная[этот], это означает, что член доступен только для каждого экземпляра. Это становится более ясным в следующем примере:

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

Как вы можете видеть, второй Foo не имеет никаких проблем, так как любой экземпляр может получить доступ к частному val i. однако для первого Foo есть ошибка, так как каждый экземпляр не может видеть i другого экземпляра.

это хорошая практика, чтобы написать частный[это], так как это накладывает большее ограничение.

в большинстве языков программирования ООП, таких как java, частные поля/методы означают, что эти частные поля/методы недоступны вне класса. Однако экземпляры / объекты одного класса могут иметь доступ к закрытым полям объектов с помощью оператора присваивания или с помощью конструктора копирования. В Scala private[this] является объектом private,который гарантирует, что любой другой объект того же класса не сможет получить доступ к private[this] члены.

пример

1.Без личного[этого]

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.Используя private [this]

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

  }
}

следовательно, private[this] гарантирует, что поле _password доступно только с этим.

чтобы подробнее остановиться на вопросе производительности Алексей Романов упомянул, вот некоторые из моих догадок. Цитаты из книги "программирование в Scala: полное пошаговое руководство, 2-е издание" раздел 18.2:

в Scala каждый var, который не является частным членом некоторого объекта, неявно определяет геттер и метод сеттера с ним.

чтобы проверить это, этот код вызовет ошибку компиляции:

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

Скала жалуется error: ambiguous reference to overloaded definition. Добавление ключевого слова override в data_= не поможет должен доказать, что метод генерируется компилятором. Добавление private ключевое слово в переменную data все равно вызовет эту ошибку компиляции. Однако, следующий код компилируется нормально:

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

Итак, я думаю private[this] не позволит scala генерировать методы getter и setter. Таким образом, доступ к такой переменной позволит сэкономить накладные расходы на вызов метода getter и setter.

должен ли я всегда использовать его по умолчанию? Или я должен использовать его только в некоторых конкретные случаи, когда мне нужно явно ограничить изменение поля значение даже для объектов одного класса? Другими словами, как я должен выбор между

лучше использовать private[this] Если вы планируете синхронизировать переменную.

вот хороший пример от руководство по стилю scala команды 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 }
}

Comments

    Ничего не найдено.