私人 vs私人
在斯卡拉我看到这样的function作为对象私有variables。 从我不是非常丰富的Java背景中,我学会了closures所有东西(使之成为私有),并在必要时打开(提供访问器)。 Scala引入了更加严格的访问修饰符。 我应该总是默认使用它? 还是应该仅在某些特定情况下使用它,即使是对于同一类的对象,我也需要显式限制更改的字段值? 换句话说,我应该如何select
class Dummy { private var name = "default name" } class Dummy { private[this] var name = "default name" }
第二个是更严格的,我喜欢它,但我应该总是使用它,或者只有当我有一个强有力的理由?
编辑:正如我在这里看到私人[这]只是一些子情况下,而不是我可以使用其他修饰:“包,类或单身对象”。 所以我会留下一些特殊情况。
我不认为这太重要,因为任何变化只会触及一个类别。 所以selectprivate
不是protected
public
的最重要的原因是不适用的。
在性能真正重要的地方使用private[this]
(因为这样可以直接访问字段而不是方法)。 否则,只要定下一种风格,所以人们不需要弄清楚为什么这个属性是private
, 而且是private[this]
。
有一个情况下需要private[this]
来编译代码。 这与方差符号和可变variables的相互作用有关。 考虑下面的(无用的)类:
class Holder[+T] (initialValue: Option[T]) { // without [this] it will not compile private[this] var value = initialValue def getValue = value def makeEmpty { value = None } }
所以这个类被devise为保存一个可选的值,作为一个选项返回它,并使用户能够调用makeEmpty
清除值(因此var)。 如上所述,除了certificate这一点之外,这是无用的。
如果您尝试使用private
而不是private
来编译此代码,则会失败,并显示以下错误消息:
错误:协变typesT出现在types为Value的typesOption [T]中的逆变换位置上。class = Holder [+ T](initialValue:Option [T]){
发生此错误是因为值是协变typesT(+ T)上的可变variables,通常这是一个问题,除非标记为私有的private[this]
的实例。 编译器在差异检查中有特殊的处理来处理这种特殊情况。
所以它是深奥的,但有一个情况下, private[this]
是需要超过private
。
private var name
可以从class Dummy
(及其伴随object Dummy
)的任何方法访问。
private[this] var name
只能从this
对象的方法访问,而不能从class Dummy
其他对象访问。
private [this](相当于protected [this])意味着“y”只对同一个实例中的方法可见。 例如,你不能在equals方法中的第二个实例上引用y,即“this.y == that.y”会在“that.y”上产生编译错误。 (资源)
所以你可以在每次你想要的时候做私人的事情,但是如果你需要的话可以有一些问题
这是用scala 2.11.5testing的。 考虑下面的代码
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'不是。
有关访问修饰符的更多详细信息,请参阅“Scala编程:详尽的分步指南”一书的第13.5节。
当将范围添加到私有修饰符( private [X] )时,它有效地performance为“最多”X,其中X指定一些封装的包,类或单例对象。
例如, private bar [bar] ,其中bar是一个包,意味着属于包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。 但是对于第一个Foo来说,由于每个实例都看不到其他实例的i,所以出现错误。
写私人书这是一个很好的做法,因为它施加了更大的限制。
为了详细说明Alexey Romanov提到的性能问题,下面是我的一些猜测。 从“Scala编程:综合循序渐进指南,第二版”一书中引用第18.2节:
在Scala中,每个var都是非私有成员,它隐式地定义了一个getter和一个setter方法。
为了testing它,这段代码会导致编译错误:
class PrivateTest{ var data: Int = 0 def data_=(x : Int){ require(x > 0) data = x } }
斯卡拉抱怨error: ambiguous reference to overloaded definition
。 将override关键字添加到data_=
将无助于certificate该方法是由编译器生成的。 将private
关键字添加到variablesdata
仍然会导致此编译错误。 但是,下面的代码编译罚款:
class PrivateTest{ private[this] var data: Int = 0 def data_=(x : Int){ require(x > 0) data = x } }
所以,我猜private[this]
会阻止scala生成getter和setter方法。 因此,访问这样的variables将节省调用getter和setter方法的开销。
我应该总是默认使用它? 还是应该仅在某些特定情况下使用它,即使是对于同一类的对象,我也需要显式限制更改的字段值? 换句话说,我应该如何select
如果您打算同步variables,最好使用private[this]
。
Spark团队的Scala风格指南是一个很好的例子:
// 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 } }
在像Java这样的大多数OOP编程语言中,私有字段/方法意味着这些私有字段/方法不能在类之外访问。 但是,相同类的实例/对象可以使用赋值运算符或复制构造函数访问对象的专用字段。 在Scala中,private [this]是私有对象,它确保同一类的任何其他对象不能访问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.使用私人[这个]
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字段只能用这个来访问。