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

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

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

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

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

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

Ответ 1

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

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

Ответ 2

Существует случай, когда 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_ =     class Holder [+ T] (initialValue: Option [T]) {

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

Это было протестировано с использованием 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" можно получить только из экземпляра, к которому он принадлежит. Итак, "this.x" отлично, но "other.x" не является.

Более подробную информацию о модификаторах доступа можно найти в разделе 13.5 "Программирование в Scala: Всеобъемлющее пошаговое руководство".

Ответ 6

При добавлении области действия к модификатору private (private [X]) он эффективно ведет себя как "до" X, где X обозначает какой-либо охватывающий пакет, class или singleton.

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

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

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.

Хорошая практика для написания частного [это], поскольку она налагает большее ограничение.

Ответ 7

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

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

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

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

Scala жалуется на 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 методов генерации и setter. Таким образом, доступ к такой переменной позволит сэкономить накладные расходы при вызове метода getter и setter.

Ответ 8

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

Лучше использовать 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 }
}

Ответ 9

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

Пример

1. Без частного [this]

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. Использование частного [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 доступно только с этим.