복붙노트

[SCALA] 어떻게 경우 클래스 동반자에 적용 오버라이드 (override)

SCALA

어떻게 경우 클래스 동반자에 적용 오버라이드 (override)

그래서 여기 상황이다. 그래서 같은 경우 클래스를 정의하려면 :

case class A(val s: String)

그리고 내가 클래스의 인스턴스를 만들 때의 '값이 너무 좋아, 항상 대문자 수 있도록 객체를 정의하려면 :

object A {
  def apply(s: String) = new A(s.toUpperCase)
}

방법 두 번 정의 : 스칼라가 적용 (문자열들)이 불평하기 때문에 그러나이 작동하지 않습니다. 나는 케이스 클래스 구문을 자동으로 나를 위해 그것을 정의하는 것을 이해하지만, 내가 이것을 달성 할 수있는 또 다른 방법이 없다? 나는 패턴 매칭을 위해 그것을 사용하려는 때문에 나는 경우 클래스를 고수하고 싶습니다.

해결법

  1. ==============================

    1.갈등의 이유는 케이스 클래스는 동일한 적용 () 메소드 (동일한 서명)을 제공하는 것입니다.

    갈등의 이유는 케이스 클래스는 동일한 적용 () 메소드 (동일한 서명)을 제공하는 것입니다.

    우선 당신이 필요로 사용하는 것이 좋습니다 싶습니다 :

    case class A(s: String) {
      require(! s.toCharArray.exists( _.isLower ), "Bad string: "+ s)
    }
    

    사용자가 S가 소문자 문자를 포함하는 인스턴스를 만들려고 경우에 예외를 throw합니다. 생성자에 넣어 무엇을 또한 패턴 매칭 (일치)을 사용할 때 나가 무엇 때문에이 경우 클래스의 좋은 사용하는 것입니다.

    이 없습니다 당신이 원하는 경우, 나는 개인 생성자를 만들 만이 방법을 적용 사용하는 사용자를 강제 :

    class A private (val s: String) {
    }
    
    object A {
      def apply(s: String): A = new A(s.toUpperCase)
    }
    

    보시다시피, A는 더 이상 경우 클래스입니다. 이름 "케이스 클래스"는 일치를 사용하여 (수정되지 않은) 생성자 인자를 추출 할 수 있어야 의미하기 때문에 불변 필드가있는 경우 클래스가, 입력 값의 수정을 위해 의미가 있는지 확실하지 않다.

  2. ==============================

    2.UPDATE 2016년 2월 25일 : 나는 아래에 쓴 답이 충분히 남아 있지만, 그것은 또한 케이스 클래스의 동반자 개체에 대한이 또 다른 관련 대답을 참조 할 가치가있다. 하나는 케이스 클래스 자체를 정의 할 때 즉, 하나는 정확히 컴파일러 생성 된 암시 적 동반자 개체를 재현 않는 방법되는 발생합니다. 나를 위해, 그것은 카운터 직관적으로 밝혀졌다.

    UPDATE 2016년 2월 25일 : 나는 아래에 쓴 답이 충분히 남아 있지만, 그것은 또한 케이스 클래스의 동반자 개체에 대한이 또 다른 관련 대답을 참조 할 가치가있다. 하나는 케이스 클래스 자체를 정의 할 때 즉, 하나는 정확히 컴파일러 생성 된 암시 적 동반자 개체를 재현 않는 방법되는 발생합니다. 나를 위해, 그것은 카운터 직관적으로 밝혀졌다.

    요약: 여전히 유효한 (을 ated) ADT (추상 데이터 유형)를 유지하면서이 매우 간단 경우 클래스에 저장하기 전에 케이스 클래스 매개 변수의 값을 변경할 수 있습니다. 이 솔루션은 비교적 간단하지만, 세부 사항을 발견하는 것은 아주 조금 더 도전이었다.

    세부: 당신이 당신의 케이스 클래스의 유효한 인스턴스를 확인하려면 이제까지 당신이해야 할 일의 숫자가, ADT (추상 데이터 형식) 뒤의 필수 전제 인 인스턴스화 할 수 있습니다.

    예를 들어, 컴파일러 생성 복사 방법은 경우에 클래스를 기본적으로 제공한다. 그래서, 당신은 인스턴스를 보장하기 위해 매우 조심하더라도 명시 적 동반자를 통해 생성 된의 그들은 오직 대문자 값을 포함 할 수있는 보장 방법을 적용 객체, 소문자 값을 가진 경우 클래스의 인스턴스를 생성 할 것이다 다음 코드 :

    val a1 = A("Hi There") //contains "HI THERE"
    val a2 = a1.copy(s = "gotcha") //contains "gotcha"
    

    또한, 케이스 클래스는 java.io.Serializable을 구현합니다. 이것은 오직 대문자 인스턴스가 당신의주의 전략은 간단한 텍스트 편집기 및 직렬화와 전복 될 수 있다는 것을 의미한다.

    그래서, (박애 및 / 또는 malevolently) 귀하의 경우 클래스가 사용할 수있는 모든 다양한 방법을 여기에 수행해야 할 작업은 다음과 같습니다

    여기에 위의 작업과 수정 된 코드는 다음과 같습니다

    object A {
      def apply(s: String, i: Int): A =
        new A(s.toUpperCase, i) {} //abstract class implementation intentionally empty
    }
    abstract case class A private[A] (s: String, i: Int) {
      private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
        A.apply(s, i)
      def copy(s: String = s, i: Int = i): A =
        A.apply(s, i)
    }
    

    그리고 여기합니다 (@ollekullberg 응답에서 제안)에 필요한 구현하고 또한 캐싱의 어떤 종류를 넣어 이상적인 장소를 확인 후 코드는 다음과 같습니다

    object A {
      def apply(s: String, i: Int): A = {
        require(s.forall(_.isUpper), s"Bad String: $s")
        //TODO: Insert normal instance caching mechanism here
        new A(s, i) {} //abstract class implementation intentionally empty
      }
    }
    abstract case class A private[A] (s: String, i: Int) {
      private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
        A.apply(s, i)
      def copy(s: String = s, i: Int = i): A =
        A.apply(s, i)
    }
    

    이 코드는 자바 상호 운용성을 통해 사용 (구현으로 케이스 클래스를 숨기고 유도를 방지하는 최종 클래스를 생성) 될 경우 그리고이 버전은 / 강력하고 더 안전합니다 :

    object A {
      private[A] abstract case class AImpl private[A] (s: String, i: Int)
      def apply(s: String, i: Int): A = {
        require(s.forall(_.isUpper), s"Bad String: $s")
        //TODO: Insert normal instance caching mechanism here
        new A(s, i)
      }
    }
    final class A private[A] (s: String, i: Int) extends A.AImpl(s, i) {
      private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
        A.apply(s, i)
      def copy(s: String = s, i: Int = i): A =
        A.apply(s, i)
    }
    

    이 직접 질문에 대한 대답하지만, 예를 캐싱을 넘어 케이스 클래스의 주위에이 경로를 확장 할 수있는 다양한 방법이 있습니다. 내 자신의 프로젝트의 요구를 들어, 내가 코드 검토 (A StackOverflow의 자매 사이트)에 문서화 더욱 넓은 솔루션을 만들었습니다. 당신이 그것을 통해 찾고 사용하거나 내 솔루션을 활용 끝날 경우, 나에게 피드백, 제안 또는 질문과 이유를 내, 내가 하루 이내에 응답하기 위해 최선을 다하겠습니다을 떠나 고려하시기 바랍니다.

  3. ==============================

    3.나는 (즉도 가능한 경우) 동반자 객체의 적용 방법을 재정의하는 방법을 알고하지 않습니다하지만 당신은 또한 대문자 문자열에 대한 특별한 유형을 사용할 수 있습니다 :

    나는 (즉도 가능한 경우) 동반자 객체의 적용 방법을 재정의하는 방법을 알고하지 않습니다하지만 당신은 또한 대문자 문자열에 대한 특별한 유형을 사용할 수 있습니다 :

    class UpperCaseString(s: String) extends Proxy {
      val self: String = s.toUpperCase
    }
    
    implicit def stringToUpperCaseString(s: String) = new UpperCaseString(s)
    implicit def upperCaseStringToString(s: UpperCaseString) = s.self
    
    case class A(val s: UpperCaseString)
    
    println(A("hello"))
    

    위의 코드를 출력 :

    A(HELLO)
    

    당신은이 질문에 대해 살펴해야하고 대답입니다 : 스칼라 : 그것은 기본 케이스 클래스 생성자를 오버라이드 (override) 할 수 있습니까?

  4. ==============================

    4.스칼라 2.12.2+로, 스칼라는 기본적으로 적용 취소 적용하고 재정의 허용 4 월 2017 년 후이 글을 읽는 사람들을 위해. 당신은 -Xsource을 제공하여이 동작을 얻을 수 있습니다뿐만 아니라 스칼라 2.11.11+에 컴파일러 2.12 옵션을 선택합니다.

    스칼라 2.12.2+로, 스칼라는 기본적으로 적용 취소 적용하고 재정의 허용 4 월 2017 년 후이 글을 읽는 사람들을 위해. 당신은 -Xsource을 제공하여이 동작을 얻을 수 있습니다뿐만 아니라 스칼라 2.11.11+에 컴파일러 2.12 옵션을 선택합니다.

  5. ==============================

    5.케이스 클래스를 유지하고 암시 인증 된 정의 또는 다른 생성자가없는 동안 또 다른 아이디어의 서명이 약간 다르지만 사용자 관점 같은에서 적용하는 것입니다. 어딘가에 나는 암시 적 트릭을 봐 왔지만, / 기억 그것이 암시하는 인자 발견 할수 없어, 그래서 여기에 부울을 선택했다. 누군가가 나를 도와 트릭을 완료 할 수 있다면 ...

    케이스 클래스를 유지하고 암시 인증 된 정의 또는 다른 생성자가없는 동안 또 다른 아이디어의 서명이 약간 다르지만 사용자 관점 같은에서 적용하는 것입니다. 어딘가에 나는 암시 적 트릭을 봐 왔지만, / 기억 그것이 암시하는 인자 발견 할수 없어, 그래서 여기에 부울을 선택했다. 누군가가 나를 도와 트릭을 완료 할 수 있다면 ...

    object A {
      def apply(s: String)(implicit ev: Boolean) = new A(s.toLowerCase)
    }
    case class A(s: String)
    
  6. ==============================

    6.그것은 VAR 변수와 함께 작동합니다 :

    그것은 VAR 변수와 함께 작동합니다 :

    case class A(var s: String) {
       // Conversion
       s = s.toUpperCase
    }
    

    이 연습은 분명히 경우 클래스 대신 다른 생성자를 정의 권장합니다. 객체를 복사 할 때, 당신은 또한 같은 수정을 유지 .. 여기를 참조하십시오.

  7. ==============================

    7.저도 같은 문제에 직면하고이 솔루션은 나를 위해 괜찮습니다 :

    저도 같은 문제에 직면하고이 솔루션은 나를 위해 괜찮습니다 :

    sealed trait A {
      def s:String
    }
    
    object A {
      private case class AImpl(s:String)
      def apply(s:String):A = AImpl(s.toUpperCase)
    }
    

    어떤 방법이 필요한 경우에, 단지 특성에 정의 케이스 클래스에 우선합니다.

  8. ==============================

    8.당신은 당신이 기본적으로 무시 못할 또는 @ 메 흐멧 - 엠레을 가리 켰을 때, 컴파일러 플래그를 추가 할 해달라고 곳 오래된 스칼라와 함께 붙어, 당신이 경우 클래스를 필요로하는 경우, 다음을 수행 할 수 있습니다 :

    당신은 당신이 기본적으로 무시 못할 또는 @ 메 흐멧 - 엠레을 가리 켰을 때, 컴파일러 플래그를 추가 할 해달라고 곳 오래된 스칼라와 함께 붙어, 당신이 경우 클래스를 필요로하는 경우, 다음을 수행 할 수 있습니다 :

    case class A(private val _s: String) {
      val s = _s.toUpperCase
    }
    
  9. ==============================

    9.나는 이것이 당신이 이미 원하는 방법을 정확하게 작동합니다 생각합니다. 여기 내 REPL 세션입니다 :

    나는 이것이 당신이 이미 원하는 방법을 정확하게 작동합니다 생각합니다. 여기 내 REPL 세션입니다 :

    scala> case class A(val s: String)
    defined class A
    
    scala> object A {
         | def apply(s: String) = new A(s.toUpperCase)
         | }
    defined module A
    
    scala> A("hello")
    res0: A = A(HELLO)
    

    이 스칼라 2.8.1.final을 사용하고 있습니다

  10. from https://stackoverflow.com/questions/5827510/how-to-override-apply-in-a-case-class-companion by cc-by-sa and MIT license