복붙노트

[SCALA] 스칼라 배 정의 (2 방법은 동일한 유형의 소거가)

SCALA

스칼라 배 정의 (2 방법은 동일한 유형의 소거가)

나는 스칼라에 쓴 그것은 컴파일되지 않습니다 :

class TestDoubleDef{
  def foo(p:List[String]) = {}
  def foo(p:List[Int]) = {}
}

컴파일러는 통지 :

[error] double definition:
[error] method foo:(List[String])Unit and
[error] method foo:(List[Int])Unit at line 120
[error] have same type after erasure: (List)Unit

나는이 오류를 이해할 수 있도록 JVM이 제네릭에 대한 네이티브 지원이 없습니다 알고있다.

나는 :)하지만 난 게으른 목록 [문자열]과 목록 [지능]에 대해 래퍼를 쓸 수

나는 의심 합니다만, 목록 [문자열]을 표현하는 또 다른 방법은 목록 [지능]보다 동일한 유형이 아닌가요?

감사.

해결법

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

    1.마이클 Kramer의 생각처럼 내가 implicits를 사용하는,하지만 난 그게 더 직접적으로 적용 할 수 있다고 생각합니다 :

    마이클 Kramer의 생각처럼 내가 implicits를 사용하는,하지만 난 그게 더 직접적으로 적용 할 수 있다고 생각합니다 :

    case class IntList(list: List[Int])
    case class StringList(list: List[String])
    
    implicit def il(list: List[Int]) = IntList(list)
    implicit def sl(list: List[String]) = StringList(list)
    
    def foo(i: IntList) { println("Int: " + i.list)}
    def foo(s: StringList) { println("String: " + s.list)}
    

    나는 이것이 매우 읽기 쉽고 간단합니다 생각합니다.

    [최신 정보]

    작동하는 것 같다 다른 쉬운 방법이있다 :

    def foo(p: List[String]) { println("Strings") }
    def foo[X: ClassManifest](p: List[Int]) { println("Ints") }
    def foo[X: ClassManifest, Y: ClassManifest](p: List[Double]) { println("Doubles") }
    

    이 확장되지 않도록 모든 버전의 경우, 추가 입력 매개 변수를 필요로하지만, 나는 세 가지 또는 네 가지 버전 그것의 벌금 생각합니다.

    [업데이트 2]

    정확히 두 가지 방법을 위해 나는 또 다른 멋진 트릭을 발견 :

    def foo(list: => List[Int]) = { println("Int-List " + list)}
    def foo(list: List[String]) = { println("String-List " + list)}
    
  2. ==============================

    2.대신 더미 암시 값을 발명, 당신은 그것에 대해 정확하게 할 것으로 보인다 PREDEF에 정의 된 DummyImplicit을 사용할 수 있습니다 :

    대신 더미 암시 값을 발명, 당신은 그것에 대해 정확하게 할 것으로 보인다 PREDEF에 정의 된 DummyImplicit을 사용할 수 있습니다 :

    class TestMultipleDef {
      def foo(p:List[String]) = ()
      def foo(p:List[Int])(implicit d: DummyImplicit) = ()
      def foo(p:List[java.util.Date])(implicit d1: DummyImplicit, d2: DummyImplicit) = ()
    }
    
  3. ==============================

    3.때문에 형의 삭제의 경이로움에, 당신의 방법 '목록의 형식 매개 변수 따라서 컴파일러 오류가 동일한 서명에 두 가지 방법을 감소 컴파일시 삭제 얻을.

    때문에 형의 삭제의 경이로움에, 당신의 방법 '목록의 형식 매개 변수 따라서 컴파일러 오류가 동일한 서명에 두 가지 방법을 감소 컴파일시 삭제 얻을.

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

    4.마이클 Kramer의 솔루션을 이해하기 위해서는 암시 적 매개 변수의 종류는 중요하지 않은 것을 인식 할 필요가있다. 중요한 것은 자신의 유형이 서로 다른 점이다.

    마이클 Kramer의 솔루션을 이해하기 위해서는 암시 적 매개 변수의 종류는 중요하지 않은 것을 인식 할 필요가있다. 중요한 것은 자신의 유형이 서로 다른 점이다.

    다음 코드는 같은 방식으로 작동합니다 :

    class TestDoubleDef {
       object dummy1 { implicit val dummy: dummy1.type = this }
       object dummy2 { implicit val dummy: dummy2.type = this }
    
       def foo(p:List[String])(implicit d: dummy1.type) = {}
       def foo(p:List[Int])(implicit d: dummy2.type) = {}
    }
    
    object App extends Application {
       val a = new TestDoubleDef()
       a.foo(1::2::Nil)
       a.foo("a"::"b"::Nil)
    }
    

    JVM 바이트 코드가 암시 적 매개 변수 또는 여러 매개 변수 목록의 아무것도 알고 있기 때문에 바이트 코드 수준에서 모두 foo는 방법은 2 개의 인수를 방법이된다. callsite에서 스칼라 컴파일러 (이후까지 소거되지 않은)에 전달되는 목록의 유형을보고 (에 통과시키고, 따라서 적절한 더미 오브젝트)에 해당 통화 푸 방법을 선택한다.

    더 자세한이지만,이 방법은 암시 적 인수를 공급 부담의 호출을 완화. dummyN 객체가 TestDoubleDef 클래스에 개인 경우 사실, 심지어 작동합니다.

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

    5.빅토르 클랑 이미 말했듯이, 일반 유형은 컴파일러에 의해 삭제됩니다. 다행히도 해결 방법이있다 :

    빅토르 클랑 이미 말했듯이, 일반 유형은 컴파일러에 의해 삭제됩니다. 다행히도 해결 방법이있다 :

    class TestDoubleDef{
      def foo(p:List[String])(implicit ignore: String) = {}
      def foo(p:List[Int])(implicit ignore: Int) = {}
    }
    
    object App extends Application {
      implicit val x = 0
      implicit val y = ""
    
      val a = new A()
      a.foo(1::2::Nil)
      a.foo("a"::"b"::Nil)
    }
    

    팁을위한 Michid 주셔서 감사합니다!

  6. ==============================

    6.내가 다니엘스 응답과 산도르 Murakozis 응답을 결합 할 경우 여기에 내가 얻을 :

    내가 다니엘스 응답과 산도르 Murakozis 응답을 결합 할 경우 여기에 내가 얻을 :

    @annotation.implicitNotFound(msg = "Type ${T} not supported only Int and String accepted")   
    sealed abstract class Acceptable[T]; object Acceptable {
            implicit object IntOk extends Acceptable[Int]
            implicit object StringOk extends Acceptable[String]
    }
    
    class TestDoubleDef {
       def foo[A : Acceptable : Manifest](p:List[A]) =  {
            val m = manifest[A]
            if (m equals manifest[String]) {
                println("String")
            } else if (m equals manifest[Int]) {
                println("Int")
            } 
       }
    }
    

    나는 형태 보증 (틱) 변형을 얻을

    scala> val a = new TestDoubleDef
    a: TestDoubleDef = TestDoubleDef@f3cc05f
    
    scala> a.foo(List(1,2,3))
    Int
    
    scala> a.foo(List("test","testa"))
    String
    
    scala> a.foo(List(1L,2L,3L))
    <console>:21: error: Type Long not supported only Int and String accepted
       a.foo(List(1L,2L,3L))
            ^             
    
    scala> a.foo("test")
    <console>:9: error: type mismatch;
     found   : java.lang.String("test")
     required: List[?]
           a.foo("test")
                 ^
    

    논리는 또한 (jsuereth 덕분에)와 같은 유형 클래스에 포함될 수있다 :     @ annotation.implicitNotFound (MSG = "푸 $ {T}에만 지능 및 문자열 허용을 지원하지 않습니다")     밀봉 특성 푸 [T]를 {데프 적용 (목록 : 목록 [T]) : 단위}

    object Foo {
       implicit def stringImpl = new Foo[String] {
          def apply(list : List[String]) = println("String")
       }
       implicit def intImpl = new Foo[Int] {
          def apply(list : List[Int]) =  println("Int")
       }
    } 
    
    def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
    

    어떤 준다 :

    scala> @annotation.implicitNotFound(msg = "Foo does not support ${T} only Int and String accepted") 
         | sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
         |         implicit def stringImpl = new Foo[String] {
         |           def apply(list : List[String]) = println("String")
         |         }
         |         implicit def intImpl = new Foo[Int] {
         |           def apply(list : List[Int]) =  println("Int")
         |         }
         |       } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
    defined trait Foo
    defined module Foo
    foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
    
    scala> foo(1)
    <console>:8: error: type mismatch;
     found   : Int(1)
     required: List[?]
           foo(1)
               ^    
    scala> foo(List(1,2,3))
    Int
    scala> foo(List("a","b","c"))
    String
    scala> foo(List(1.0))
    <console>:32: error: Foo does not support Double only Int and String accepted
    foo(List(1.0))
            ^
    

    컴파일러는 암시 적으로 [푸 [A] (x)의 수단은 우리가 매개 변수를 암시 적으로 호출한다는 생각 때문에주의는 우리가 암시 적으로 작성해야한다는 [푸 [A]는. (x)를 적용한다.

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

    7.이 정말 안전 입력이 너무 좋은하지 않은 경우에도, 다른 방법 (하나 이상) :

    이 정말 안전 입력이 너무 좋은하지 않은 경우에도, 다른 방법 (하나 이상) :

    import scala.reflect.Manifest
    
    object Reified {
    
      def foo[T](p:List[T])(implicit m: Manifest[T]) = {
    
        def stringList(l: List[String]) {
          println("Strings")
        }
        def intList(l: List[Int]) {
          println("Ints")
        }
    
        val StringClass = classOf[String]
        val IntClass = classOf[Int]
    
        m.erasure match {
          case StringClass => stringList(p.asInstanceOf[List[String]])
          case IntClass => intList(p.asInstanceOf[List[Int]])
          case _ => error("???")
        }
      }
    
    
      def main(args: Array[String]) {
          foo(List("String"))
          foo(List(1, 2, 3))
        }
    }
    

    암시 적 매니페스트 paramenter은 삭제 유형을 "구체화"따라서 삭제 주위를 해킹하는 데 사용할 수 있습니다. 당신은 많은 블로그 게시물에서 더 그것에 대해 예컨대을 조금 배울 수 있습니다. 이 하나.

    무슨 일 매니페스트 PARAM 당신이 T는 삭제하기 전에 무엇 돌려 줄 수 있다는 것입니다. 그런 다음 다양한 실제 구현에 T를 기반으로 간단한 파견 나머지는 않습니다.

    아마도 패턴 매칭을 할 수있는 더 좋은 방법이있다, 그러나 나는 아직 보지 못했다. 어떤 사람들은 보통 일은 m.toString에 일치,하지만 난 (더 자세한 조금 경우에도) 클래스를 유지하는 것은 조금 청소기라고 생각합니다. 불행하게도 매니페스트의 문서는 너무 자세히되지 않은, 어쩌면 그것은 또한 그것을 단순화 할 수있는 일이있다.

    그것의 큰 단점은 정말 안전 입력하지 점이다 : 당신은 문제가있는 것입니다 그것을 처리 할 수없는 경우 foo는이 모든 T와 함께 행복 할 것이다. 나는 T에 대한 몇 가지 제약으로 해결할 수있을 것 같아요,하지만 그것을 더 복잡합니다.

    물론이 모든 물건은 가치가 당신이 게으른 특히, 그 일을하면 잘 모르겠어요, 또한 너무 좋은되지 ;-)

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

    8.대신 당신은 또한 디스패처를 사용할 수 매니페스트를 사용하는 암시 적으로 유사한 방식으로 수입 객체. 매니페스트가 오기 전에 내가 이것에 대해 블로그 : http://michid.wordpress.com/code/implicit-double-dispatch-revisited/

    대신 당신은 또한 디스패처를 사용할 수 매니페스트를 사용하는 암시 적으로 유사한 방식으로 수입 객체. 매니페스트가 오기 전에 내가 이것에 대해 블로그 : http://michid.wordpress.com/code/implicit-double-dispatch-revisited/

    이 유형의 안전 장점을 가지고 다음 오버로드 메서드는 현재 범위로 가져 디스패처이 유형의 호출 될 것입니다.

  9. ==============================

    9.내가 http://scala-programming-language.1934581.n4.nabble.com/disambiguation-of-double-definition-resulting-from-generic-type-erasure-td2327664.html에서 발견 한 멋진 트릭 아론 Novstrup로

    내가 http://scala-programming-language.1934581.n4.nabble.com/disambiguation-of-double-definition-resulting-from-generic-type-erasure-td2327664.html에서 발견 한 멋진 트릭 아론 Novstrup로

    object Baz {
        private object dummy1 { implicit val dummy: dummy1.type = this }
        private object dummy2 { implicit val dummy: dummy2.type = this } 
    
        def foo(xs: String*)(implicit e: dummy1.type) = 1
        def foo(xs: Int*)(implicit e: dummy2.type) = 2
    } 
    

    [...]

  10. ==============================

    10.나는 표준 증거 한 세트 가져올 수보다 간결한 객체를 만들기 위해 아론 Novstrup의 레오의 응답에 개선했습니다.

    나는 표준 증거 한 세트 가져올 수보다 간결한 객체를 만들기 위해 아론 Novstrup의 레오의 응답에 개선했습니다.

    final object ErasureEvidence {
        class E1 private[ErasureEvidence]()
        class E2 private[ErasureEvidence]()
        implicit final val e1 = new E1
        implicit final val e2 = new E2
    }
    import ErasureEvidence._
    
    class Baz {
        def foo(xs: String*)(implicit e:E1) = 1
        def foo(xs: Int*)(implicit e:E2) = 2
    }
    

    하지만 그 foo는 동일한 유형의 암시 적 매개 변수를 필요로 다른 방법을 호출 할 때 암시 적 값에 대한 모호한 선택이 있다는 것을 불평하는 컴파일러의 원인이됩니다.

    따라서 나는 어떤 경우에는 더 간결 만 다음을 제공합니다. 그리고이 개선 값 클래스 (AnyVal을 확장하는 것)와 함께 작동합니다.

    final object ErasureEvidence {
       class E1[T] private[ErasureEvidence]()
       class E2[T] private[ErasureEvidence]()
       implicit def e1[T] = new E1[T]
       implicit def e2[T] = new E2[T]
    }
    import ErasureEvidence._
    
    class Baz {
        def foo(xs: String*)(implicit e:E1[Baz]) = 1
        def foo(xs: Int*)(implicit e:E2[Baz]) = 2
    }
    

    포함하는 형식 이름이 다소 긴 경우, 더 간결하게 내부 특성을 선언합니다.

    class Supercalifragilisticexpialidocious[A,B,C,D,E,F,G,H,I,J,K,L,M] {
        private trait E
        def foo(xs: String*)(implicit e:E1[E]) = 1
        def foo(xs: Int*)(implicit e:E2[E]) = 2
    }
    

    그러나 값 클래스는 내부 특성, 클래스 나 객체를 허용하지 않습니다. 따라서 아론 Novstrup의 레오의 답변 값 클래스를 작동하지 마십시오.

  11. ==============================

    11.나는 이것을 테스트하지 못했지만, 왜 상한 일은하지 않을까요?

    나는 이것을 테스트하지 못했지만, 왜 상한 일은하지 않을까요?

    def foo[T <: String](s: List[T]) { println("Strings: " + s) }
    def foo[T <: Int](i: List[T]) { println("Ints: " + i) }
    

    합니까 foo는에서 변화에 대한 삭제 번역 (목록 [모든]의) 두 번, foo는에 (목록 [문자열]의)와 foo는 (목록 [지능] I) :

    http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ108

    나는 버전 2.8에서 상한 지금 대신 항상 모든의, 그런 식으로 인코딩 된 것을 읽을 생각합니다.

    공변 유형에 대한 과부하에 (? 아 내가 거기 아니라고 생각 ... 스칼라에서 같은 구문이 있지만, 주요 솔루션 위의 개념 부록으로 다음을) 구속 불변을 사용합니다 :

    def foo[T : String](s: List[T]) { println("Strings: " + s) }
    def foo[T : String2](s: List[T]) { println("String2s: " + s) }
    

    그때는 암시 적 캐스팅이 코드의 삭제 버전 제거 추정.

    UPDATE : 문제는 JVM이 "필요"보다 메소드 서명에 대한 자세한 형식 정보가 삭제한다는 것입니다. 나는 링크를 제공했다. 그것은 종류의 생성자에서 그 형태 변수의 경계에도 콘크리트 형의 변수를 삭제합니다. 아무 개념이 아닌 구체화 장점은 컴파일 타임에 알려져 있고, 일반의 인스턴스에 따라 변화하지 않는 한 함수의 유형, 바인딩 지우기에 없기 때문에 개념 구분이있다, 그것은되지 전화에 발신자에 필요한 이 삭제 된 경우 바인딩 유형을 준수하지 않는 유형과 기능, 그래서 어떻게 JVM은 바인딩 유형을 적용 할 수 있습니다? 그럼 하나 개의 링크는 바인딩 유형이 컴파일러는 액세스 해야하는 메타 데이터에 유지됩니다 말한다. 오버로드 사용하지 않는 타입의 경계를 사용하는 이유를 설명 해준다. 유형 경계 방법이 너무 같은 안전하지 않은 일을하지 않을 것 JVM 디자이너 가정 실례 입력 범위 (싸!)없이 호출 할 수 있기 때문에 JVM은 활짝 열려 보안 구멍 있음을 또한 의미합니다.

    내가 쓴 당시, 나는 유래는 평가 사람들의 시스템이 명성을 통해 약간의 경쟁과 같은 답변의 품질에 의해 것을 이해하지 못했다. 나는 정보를 공유하는 장소라고 생각했다. 내가 쓴 당시, 나는 구체화을 비교하고 (다양한 언어를 비교) 개념 수준에서 비는-구체화, 그래서 내 마음에 바운드 유형을 지우려면 어떤 이해가되지 않았다.

  12. from https://stackoverflow.com/questions/3307427/scala-double-definition-2-methods-have-the-same-type-erasure by cc-by-sa and MIT license