왜이 문자가 인쇄됩니까? 패턴 일치가 구조 유형에서 작동하지 않습니까?스칼라의 패턴 일치 구조 유형
"hello" match {
case s: { def doesNotExist(i: Int, x: List[_]): Double } => println("wtf?")
case _ => println("okie dokie")
}
왜이 문자가 인쇄됩니까? 패턴 일치가 구조 유형에서 작동하지 않습니까?스칼라의 패턴 일치 구조 유형
"hello" match {
case s: { def doesNotExist(i: Int, x: List[_]): Double } => println("wtf?")
case _ => println("okie dokie")
}
(scala -unchecked
)에서 확인 경고와 스칼라 인터프리터이 예제를 실행하면 다음과 같은 경고를 생성합니다 warning: refinement AnyRef{def doesNotExist(Int,List[_]): Double} in type pattern is unchecked since it is eliminated by erasure
. 불행히도, JVM이 제네릭을 구체화하지 않았기 때문에 이와 같은 제네릭 타입은 런타임에 확인할 수 없다. JVM이이 패턴 일치에보고
모든입니다
"hello" match {
case s: Object => ...
case annon: Object => ...
}
편집 : 귀하의 의견에 응답, 나는 해결책에 대해 생각되었지만 어제를 게시 할 시간이 없었다 . 불행하게도, 이 일 때도 컴파일러는 적절한 Manifest
을 삽입하지 못합니다.
해결하려는 문제는 객체가 주어진 구조 유형인지 비교하는 것입니다. 여기
type Foo = AnyRef { def doesNotExist(i: Int, x: List[_]): Double }
def getManifest[T](implicit m: Manifest[T]) = m
def isFoo[T](x: T)(implicit mt: Manifest[T]) =
mt == getManifest[Foo]
방법 isFoo
을 (스칼라 2.7.6.final 내게 몇 번 추락으로 비슷한 아이디어를 재생하는 동안, 스칼라 2.8 r20019) 내가 생각하고 봤는데 몇 가지 코드의 기본적의 매니페스트를 비교 등급 x
은 Foo
이다. 이상적인 세계에서 구조 유형의 적하 목록은 필요한 방법을 포함하는 모든 유형의 적하 목록과 동일해야합니다. 적어도 그건 내 생각의 기차 야. 컴파일러가 getManifest[Foo]
을 호출 할 때 대신에 Manifest[AnyRef]
을 삽입하기 때문에 불행하게도이 컴파일이 실패합니다. 흥미롭게도 구조 형식 (예 : type Foo = String
)을 사용하지 않으면이 코드가 컴파일되어 예상대로 작동합니다. 어느 시점에 질문을 게시하여 구조 유형에 실패한 이유를 확인합니다. 이는 설계상의 결정인지 실험 반사 API의 문제 일뿐입니다.
자바 리플렉션을 사용하면 객체에 메소드가 있는지 항상 확인할 수 있습니다.
containsMethod("foo", "concat", classOf[String]) // true
containsMethod("foo", "bar", classOf[List[Int]]) // false
를 ...하지만 그것은 아주 좋은 아니에요 : 작동
def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {
try {
x.getClass.getMethod(name, params: _*)
true
}
catch {
case _ => false
}
}
예상대로.
또한 구조 유형의 구조는 런타임에 사용할 수 없습니다. 방법이 def foo(x: {def foo: Int}) = x.foo
인 경우 지우는 후 def foo(x: Object) = [some reflection invoking foo on x]
, 형식 정보가 손실됩니다. 그래서 반사가 처음 사용되는 이유는 Object
에서 메소드를 호출해야하고, Object
에 해당 메소드가 있는지 JVM이 알지 못하기 때문입니다. 당신이 반사를 사용해야 할 거라면
고마워, Flaviu. 그건 내 질문에 대한 답변. 그러나 이것은 구조가 실제로 리플렉션을 통해 런타임에 사용할 수있는 것이기 때문에 이것이 달성 할 수있는 가장 좋은 방법이 무엇인지 궁금합니다. 그것을 얻는 것은 단지 서투른 것이다. 후속 조치에 대한 감사합니다. –
. 매우 흥미로운 것들. –
, 적어도 그것이 추출기와 함께 멋진 보이게 할 수 있습니다
object WithFoo {
def foo(){
println("foo was called")
}
}
object HasFoo {
def containsMethod(x: AnyRef, name: String, params: Array[java.lang.Class[_]]) : Boolean = {
try {
x.getClass.getMethod(name, params: _*)
true
} catch {
case _ => false
}
}
def unapply(foo:AnyRef):Option[{def foo():Unit}] = {
if (containsMethod(foo, "foo", new Array[Class[_]](0))) {
Some(foo.asInstanceOf[{def foo():Unit}])
} else None
}
}
WithFoo.asInstanceOf[AnyRef] match {
case HasFoo(foo) => foo.foo()
case _ => println("no foo")
}
'HasFoo'를 더 유연하게 정의 할 수 있다면 좋을 것입니다. 예를 들어, val HasFoo = new [{def foo() : Unit}] ("foo")가 있습니다.나는 그 방법을 시도했지만,'{def foo (i : Int) : Int}'와 같은 복잡한 타입에 대해서는 여전히 문제가있는 것 같습니다. – Debilski
왜 컴파일러가 자동으로이 작업을 수행하지 않습니까? – Gabriel
'containsMethod'는'Try (x.getClass.getMethod (name, params : _ *)). isSuccess'로 탈수 될 수 있습니다. –
나는 당신의 코멘트 : 비추어 내 대답을 확장했습니다. –