частный [это] против частного
в Scala я вижу такую функцию, как object-private variable. Из моего не очень богатого Java-фона я научился закрывать все (делать его частным) и открывать (предоставлять доступы), если это необходимо. Scala вводит еще более строгий модификатор доступа. Должен ли я всегда использовать его по умолчанию? Или я должен использовать его только в некоторых конкретных случаях, когда мне нужно явно ограничить изменение значения поля даже для объектов одного класса? Другими словами, как я должен выбирать между
class Dummy {
private var name = "default name"
}
class Dummy {
private[this] var name = "default name"
}
В второй-более строгий, и мне это нравится, но я должен всегда использовать или только если у меня есть веская причина?
отредактировано: как я вижу здесьprivate[this] просто некоторые ней и вместо this Я могу использовать другие модификаторы: "пакет, класс или объект-синглтон". Так что я оставлю это для какого-нибудь особого случая.
9 ответов:
Я не думаю, что это имеет слишком большое значение, так как любые изменения будут касаться только одного класса в любом случае. Так что самая главная причина предпочесть
privateoverprotectedoverpublicне относится.использовать
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