private [this] 대 private


112

Scala에서는 객체-개인 변수와 같은 기능을 볼 수 있습니다. 별로 풍부하지 않은 Java 배경에서 필요한 경우 모든 것을 닫고 (비공개로) 열고 (접근자를 제공) 배웠습니다. Scala는 훨씬 더 엄격한 액세스 수정자를 도입합니다. 항상 기본적으로 사용해야합니까? 아니면 동일한 클래스의 객체라도 필드 값 변경을 명시 적으로 제한해야하는 특정 경우에만 사용해야합니까? 즉, 어떻게 선택해야합니까?

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

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

두 번째는 더 엄격하고 좋아하지만 항상 사용해야합니까 아니면 강력한 이유가있을 때만 사용해야합니까?

편집 됨 : 여기에서 볼 수 있듯이 private[this]일부 하위 사례가 있으며 대신 this다른 수정자를 사용할 수 있습니다 : "패키지, 클래스 또는 단일 객체". 그래서 특별한 경우를 위해 남겨 두겠습니다.


답변:


59

변경 사항은 어느 쪽이든 한 클래스에만 영향을 미치기 때문에 너무 중요하다고 생각하지 않습니다. 가장 중요한 이유는 선호하는 그래서 private이상 protected이상 public적용되지 않습니다.

private[this]성능이 정말로 중요한 곳에 사용하십시오 (이 방법 대신 직접 필드 액세스를 얻을 수 있기 때문입니다). 그렇지 않으면, 사람들 이이 속성이 왜 private이고 속성 이 private[this].


6
@ om-nom-nom 사실, 말할 것도 많지 않습니다. JIT는 private어쨌든 생성 된 접근 자 메서드 호출을 인라인해야 하므로 영향은 0이거나 최소한 매우 작아야합니다.
Alexey Romanov

9
이 답변은 오해의 소지가 있으며 실제 이유는 선언 사이트 차이입니다 (이 답변 참조 : stackoverflow.com/a/9727849/445715 ).
안드레이 Breslav

1
@AndreyBreslav 나는이 것을 동의 이유. 예, 그러한 경우가 존재하지만 대답에 따르면 매우 드뭅니다.
Alexey Romanov

3
흠. 아래의 Marek Adamek의 대답은 private [this]를 private보다 선택하는 진짜 이유 인 것 같습니다. 의도는 클래스의 모든 인스턴스가 아닌 특정 인스턴스에 대한 액세스를 제한하는 것입니다.
Ram Rajamony 2015

3
@AlexeyRomanov-질문은 "항상 기본적으로 사용해야합니까?"라고 묻습니다. 같은 클래스의 다른 인스턴스에서 필드가 필요하면 private [this]를 사용할 수 없다고 말함으로써 답변을 향상시킬 수 있다고 생각합니다.
Ram Rajamony 2015

130

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_ = 클래스 홀더 [+ T]의 유형 Option [T]에서 반 변성 위치에서 발생합니다. (initialValue : Option [T]) {

이 오류는 값이 공변 유형 T (+ T)에서 변경 가능한 변수이기 때문에 발생하며 private[this]. 컴파일러는이 특별한 경우를 처리하기 위해 분산 검사에서 특별한 처리를합니다.

그래서 그것은 난해하지만 private[this]이상이 필요한 경우 가 private있습니다.


1
변경 가능성이 혼합되어있을 때 실패하는 이유를 알 수 있지만 변경 가능한 항목이 없는데도 동일한 오류가 발생하는 이유는 무엇입니까?
Matt Kantor 2015

35

private var name임의의 방법에서 액세스 class Dummy(및 동반자 object Dummy).

private[this] var namethis다른 개체가 아닌 개체의 메서드 에서만 액세스 할 수 있습니다 class Dummy.


18

private [this] (protected [this]와 동일)는 "y"가 동일한 인스턴스의 메소드에만 표시됨을 의미합니다. 예를 들어 equals 메서드의 두 번째 인스턴스에서 y를 참조 할 수 없습니다. 즉, "this.y == that.y"는 "that.y"에 대한 컴파일 오류를 생성합니다. (출처)

그래서 당신은 당신이 원할 때마다 private [this]를 할 수 있지만 당신이 그것을 참조해야 할 경우 약간의 문제가있을 수 있습니다


13
private[this]과 같지 않습니다 protected[this]. protected[this]서브 클래스 인스턴스가 멤버에 액세스 할 수 있습니다.
drexin

당신은 할 수 있습니다 this.y == that.y[이]가, 난 그냥 둘 다 시도 개인이나 개인도 사용
lisak

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

이 자바 (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 절을 참조하십시오.


1
질문은 무슨 private[this]뜻 인지 묻는 것이 아닙니다 . 첫 번째 문장에 유의하십시오.
Alexey Romanov

9

private 한정자 ( private [X] )에 범위를 추가하면 효과적으로 "최대"X로 작동합니다. 여기서 X는 일부 둘러싸는 패키지, 클래스 또는 단일 개체를 지정합니다.

예를 들어, 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는 모든 인스턴스가 private val i에 액세스 할 수 있기 때문에 문제가 없습니다. 그러나 첫 번째 Foo에는 각 인스턴스가 다른 인스턴스의 i를 볼 수 없기 때문에 오류가 있습니다.

더 큰 제한을 부과하기 때문에 private [this]를 작성하는 것이 좋습니다.


6

Java와 같은 대부분의 OOP 프로그래밍 언어에서 개인 필드 / 메소드는 이러한 개인 필드 / 메서드가 클래스 외부에서 액세스 할 수 없음을 의미합니다. 그러나 동일한 클래스의 인스턴스 / 객체는 할당 연산자 또는 복사 생성자를 사용하여 객체의 비공개 필드에 액세스 할 수 있습니다. Scala에서 private [this]는 private [this] 개체이므로 동일한 클래스의 다른 개체가 private [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. 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 필드가 이것으로 만 액세스 할 수 있도록합니다.


이것은 가장 명확하고 더 객관적인 대답입니다.
Lucas Lima

2

Alexey Romanov가 언급 한 성능 문제에 대해 자세히 설명하기 위해 여기에 몇 가지 추측이 있습니다. "Programming in Scala : A Comprehensive Step-by-Step Guide, 2nd Edition"섹션 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]스칼라가 getter와 setter 메소드를 생성하는 것을 막을 것이라고 생각 합니다. 따라서 이러한 변수에 액세스하면 getter 및 setter 메서드를 호출하는 오버 헤드를 줄일 수 있습니다.


1

항상 기본적으로 사용해야합니까? 아니면 동일한 클래스의 객체라도 필드 값 변경을 명시 적으로 제한해야하는 특정 경우에만 사용해야합니까? 즉, 어떻게 선택해야합니까?

private[this]변수를 동기화하려는 경우 사용 하는 것이 좋습니다 .

다음 은 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 }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.