在Scala中,我将此功能视为对象私有变量。从我不太丰富的Java背景中,我学会了关闭所有内容(使其成为私有)并在必要时打开(提供访问者)。 Scala引入了更严格的访问修饰符。我应该总是默认使用它吗?或者我应该只在某些特定情况下使用它,我需要明确限制更改字段值,即使对于同一类的对象?换句话说,我应该如何选择
class Dummy {
private var name = "default name"
}
class Dummy {
private[this] var name = "default name"
}
第二个更严格,我喜欢它,但是我应该经常使用它还是只有在我有充分理由的情况下?
编辑:我看到here private[this]
只是一些子例,而不是this
我可以使用其他修饰符:“package,class或singleton object”。所以我会留下一些特殊情况。
答案 0 :(得分:119)
有一种情况需要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出现在值value_ =类型为Option [T]的逆变位置 class Holder [+ T](initialValue:Option [T]){
发生此错误是因为value是协变类型T(+ T)上的可变变量,除非使用private[this]
标记为私有,否则通常会出现问题。编译器在其方差检查中有特殊处理来处理这种特殊情况。
所以这是深奥的,但有一种情况是private[this]
需要private
。
答案 1 :(得分:59)
我认为这不重要,因为任何改变都只会触及一个班级。因此,private
优于protected
优于public
的最重要原因不适用。
使用性能真正重要的private[this]
(因为您将获得直接字段访问而不是这种方式)。否则,只需确定一种风格,这样人们就不需要弄清楚为什么此属性为private
而 属性为private[this]
。< / p>
答案 2 :(得分:27)
private var name
(及其随附class Dummy
)的任何方法访问 object Dummy
。
private[this] var name
只能从this
对象的方法访问,而不能从class Dummy
的其他对象访问。
答案 3 :(得分:16)
private [this](相当于protected [this])意味着“y”是 仅对同一实例中的方法可见。例如,你可以 不是在等于方法的第二个实例上引用y,即 “this.y == that.y”会在“that.y”上生成编译错误。 (source)
因此您可以在每次需要时私下[this]但如果您需要参考它可能会遇到问题
答案 4 :(得分:12)
使用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
但是如果您使用&#39; [this]&#39;修饰符下面的代码不会编译
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
}
}
这是因为在第一种情况下&#39; x&#39;在类级别可访问,而在第二种情况下,它是更严格的实例级别。这意味着&#39; x&#39;只能从它所属的实例访问。所以&#39; this.x&#39;很好但是其他的。&#39;不是。
您可以参考&#34; Scala编程:综合循序渐进指南&#34;中的第13.5节;有关访问修饰符的更多详细信息,请参阅。
答案 5 :(得分:7)
将范围添加到私有修饰符(私有[X] )时,它实际上表现为“最多”X,其中X表示一些封闭包, class或singleton对象。
例如, private [bar] ,其中 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,所以会出现错误。
写私人[this]是一个好习惯,因为它会施加更大的限制。
答案 6 :(得分:3)
在大多数OOP编程语言(如java)中,私有字段/方法意味着这些私有字段/方法无法在类外部访问。但是,同一类的实例/对象可以使用赋值运算符或通过复制构造函数访问对象的私有字段。在Scala中,private [this]是对象私有的,这可以确保同一个类的任何其他对象都无法访问私有[this]成员。
示例强>
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
}
}
因此私有[this]确保只有_password字段才能访问。
答案 7 :(得分:2)
详细说明Alexey Romanov提到的性能问题,以下是我的一些猜测。 书中的“Scala编程:综合循序渐进指南,第2版”第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
。将覆盖关键字添加到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方法的开销。
答案 8 :(得分:1)
我应该在默认情况下始终使用它吗?或者我应该只在某些地方使用它 我需要明确限制更改字段的特定情况 甚至对于同一类的对象的值?换句话说,我应该怎么做
之间选择
如果您计划同步变量,最好使用private[this]
。
这是scala style guide of the Spark team的一个很好的例子:
// 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 }
}