[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.마이클 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.대신 더미 암시 값을 발명, 당신은 그것에 대해 정확하게 할 것으로 보인다 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.때문에 형의 삭제의 경이로움에, 당신의 방법 '목록의 형식 매개 변수 따라서 컴파일러 오류가 동일한 서명에 두 가지 방법을 감소 컴파일시 삭제 얻을.
때문에 형의 삭제의 경이로움에, 당신의 방법 '목록의 형식 매개 변수 따라서 컴파일러 오류가 동일한 서명에 두 가지 방법을 감소 컴파일시 삭제 얻을.
-
==============================
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.빅토르 클랑 이미 말했듯이, 일반 유형은 컴파일러에 의해 삭제됩니다. 다행히도 해결 방법이있다 :
빅토르 클랑 이미 말했듯이, 일반 유형은 컴파일러에 의해 삭제됩니다. 다행히도 해결 방법이있다 :
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.내가 다니엘스 응답과 산도르 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.이 정말 안전 입력이 너무 좋은하지 않은 경우에도, 다른 방법 (하나 이상) :
이 정말 안전 입력이 너무 좋은하지 않은 경우에도, 다른 방법 (하나 이상) :
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.대신 당신은 또한 디스패처를 사용할 수 매니페스트를 사용하는 암시 적으로 유사한 방식으로 수입 객체. 매니페스트가 오기 전에 내가 이것에 대해 블로그 : http://michid.wordpress.com/code/implicit-double-dispatch-revisited/
대신 당신은 또한 디스패처를 사용할 수 매니페스트를 사용하는 암시 적으로 유사한 방식으로 수입 객체. 매니페스트가 오기 전에 내가 이것에 대해 블로그 : http://michid.wordpress.com/code/implicit-double-dispatch-revisited/
이 유형의 안전 장점을 가지고 다음 오버로드 메서드는 현재 범위로 가져 디스패처이 유형의 호출 될 것입니다.
-
==============================
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.나는 표준 증거 한 세트 가져올 수보다 간결한 객체를 만들기 위해 아론 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.나는 이것을 테스트하지 못했지만, 왜 상한 일은하지 않을까요?
나는 이것을 테스트하지 못했지만, 왜 상한 일은하지 않을까요?
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은 활짝 열려 보안 구멍 있음을 또한 의미합니다.
내가 쓴 당시, 나는 유래는 평가 사람들의 시스템이 명성을 통해 약간의 경쟁과 같은 답변의 품질에 의해 것을 이해하지 못했다. 나는 정보를 공유하는 장소라고 생각했다. 내가 쓴 당시, 나는 구체화을 비교하고 (다양한 언어를 비교) 개념 수준에서 비는-구체화, 그래서 내 마음에 바운드 유형을 지우려면 어떤 이해가되지 않았다.
from https://stackoverflow.com/questions/3307427/scala-double-definition-2-methods-have-the-same-type-erasure by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 다중 스칼라 형 패턴 매칭 (0) | 2019.11.06 |
---|---|
[SCALA] 자동으로 우아하게 스파크 SQL에 DataFrame 평평 (0) | 2019.11.06 |
[SCALA] 이클립스, 안드로이드, 스칼라 간편한 있지만 작동하지 않는 (0) | 2019.11.06 |
[SCALA] 어떻게 메서드 호출을 통해 요소를 나중에받을 수있는 소스를 만드는 방법? (0) | 2019.11.06 |
[SCALA] 왜 개인 val`와`민간 최종 val` 다른`입니까? (0) | 2019.11.06 |