私人[此事]与私人[此事]相比

在 Scala 中,我看到了对象私有变量这样的特性。从我不是很丰富的 Java 背景中,我学会了关闭所有内容(将其设为私有)并在必要时打开(提供访问器)。Scala 引入了更严格的访问修饰符。我应该一直默认使用它吗?或者我应该只在某些特定的情况下使用它,即使对于同一个类的对象,我也需要显式地限制字段值的更改?换句话说,我该如何选择

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


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

第二个更严格,我喜欢它,但我应该总是使用它还是只有当我有一个强大的理由?

编辑: 正如我所看到的,给你 private[this]只是一些子格,我可以使用其他修饰符来代替 this: “ package,class or singleton object”。所以我把它留给特殊情况。

48485 次浏览

我不认为这很重要,因为任何改变都只会影响到一个类。因此,选择 private而不是 protected而不是 public的最重要原因并不适用。

Use private[this] where performance really matters (since you'll get direct field access instead of methods this way). Otherwise, just settle on one style so people don't need to figure out why 这个 property is private and 那个 one is private[this].

Private [ this ](相当于 protected [ this ])表示“ y”是 只对同一实例中的方法可见 而不是在 equals 方法中的第二个实例上引用 y,即, “ this. y = = that. y”将在“ that. y”上生成一个编译错误。 (资料来源)

so you can do private[this] every time you want but you can have some problem if you need refer it

有一种情况需要 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 ]中的逆变位置 类 Holder [ + T ](initialValue: Option [ T ]){

出现这个错误是因为 value 是协变类型 t (+ t)上的一个变量,这通常是一个问题,除非用 private[this]标记为私有实例。编译器在其方差检查中有特殊处理来处理这种特殊情况。

So it's esoteric but there is a case where private[this] is required over private.

为了详细说明 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 方法的开销。

这是使用 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’就不行了。

关于访问修饰符的更多细节,可以参考《 Scala 编程: 全面的一步一步指南》一书的第13.5节。

private var name可以从 class Dummy的任何方法(及其同伴 object Dummy)访问。

private[this] var name只能从 this对象的方法访问,而不能从 class Dummy的其他对象访问。

我应该总是默认使用它吗? 或者我应该只在某些情况下使用它 specific cases where I need to explicitly restrict changing field 即使对于同一类别的物件,我应该怎样 choose between

如果计划同步变量,最好使用 private[this]

Here a good example from the 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)中,私有字段/方法意味着这些私有字段/方法不能从类外部访问。但是,同类的实例/对象可以使用赋值运算符或通过复制建构子访问对象的私有字段。在 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.Using 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 字段只能用 this 访问。

考虑 access _ modfier [ xxx ]的表示法,它表示目标的范围:

package demo.mxl


class PrivateThisDemo(private val aField: String, private[this] val bField: String) {
def simpleStr: String = s"aField: $aField, bField: $bField"
}


object PrivateThisDemo {
def main(args: Array[String]): Unit = {
val obj = new PrivateThisDemo("a", "b")
println(s"${obj.simpleStr}")
println(s"${obj.aField}") // compile ok
println(s"${obj.bField}") // compile error, because here out of 'this' scope
}
}