[SCALA] 어떻게 스칼라에서 제네릭 형식에 패턴 일치에?
SCALA어떻게 스칼라에서 제네릭 형식에 패턴 일치에?
이제 우리가 제네릭 클래스 컨테이너가 있다고 가정하자 :
case class Container[+A](value: A)
우리는 다음 패턴을 두 번하고의 컨테이너와 컨테이너를 일치시킬 :
val double = Container(3.3)
var container: Container[Any] = double
이를 위해, 우리는 일반적으로 작성합니다 :
container match {
case c: Container[String] => println(c.value.toUpperCase)
case c: Container[Double] => println(math.sqrt(c.value))
case _ => println("_")
}
하지만, 컴파일러는 두 경고 처음 두 경우의 각각에 대해 하나씩 제공한다. 예를 들어, 제 경고에서는 "가 소거에 의해 제거되기 때문에, 비 가변형 인수 문자열 유형 컨테이너 패턴 [문자열] 체크이다." 때문에 삭제, 그것은 다른 컨테이너의 종류 및 제 캐치 일치한다 구분하는 런타임 동안 불가능하다. 그 결과, 유형 컨테이너의 컨테이너 [더블]를 toUpperCase 방법은 이중 호출한다과 java.lang.ClassCastException가이 발생 될 수 있도록, 컨테이너 [문자열] 물체를 잡는 제 경우와 일치한다.
어떻게 특정 유형에 의해 매개 변수화 컨테이너에 맞게?
해결법
-
==============================
1.일반 rarry의 대답에서 컨테이너는 제네릭 형식의 단일 값을 포함하고 있기 때문에 귀하의 경우에, 그러나 그것은, 단순화 할 수있다, 그래서 당신이 직접 그 값의 유형에 일치시킬 수 있습니다, 올바른 :
일반 rarry의 대답에서 컨테이너는 제네릭 형식의 단일 값을 포함하고 있기 때문에 귀하의 경우에, 그러나 그것은, 단순화 할 수있다, 그래서 당신이 직접 그 값의 유형에 일치시킬 수 있습니다, 올바른 :
container match { case Container(x: String) => println("string") case Container(x: Double) => println("double") case _ => println("w00t") }
-
==============================
2.어쩌면이 도움이 될 것입니다
어쩌면이 도움이 될 것입니다
def matchContainer[A: Manifest](c: Container[A]) = c match { case c: Container[String] if manifest <:< manifest[String] => println(c.value.toUpperCase) case c: Container[Double] if manifest <:< manifest[Double] => println(math.sqrt(c.value)) case c: Container[_] => println("other") }
편집하다:
Impredicative가 지적한 바와 같이, 매니페스트는 사용되지 않습니다. 대신 다음을 수행 할 수 있습니다 :
import reflect.runtime.universe._ def matchContainer[A: TypeTag](c: Container[A]) = c match { case c: Container[String] if typeOf[A] <:< typeOf[String] => println("string: " + c.value.toUpperCase) case c: Container[Double] if typeOf[A] <:< typeOf[Double] => println("double" + math.sqrt(c.value)) case c: Container[_] => println("other") }
-
==============================
3.이에 대한 가능한 해결 방법 isInstanceOf 및 asInstanceOf을 사용할 수 있습니다.
이에 대한 가능한 해결 방법 isInstanceOf 및 asInstanceOf을 사용할 수 있습니다.
container match { case Container(x) if x.isInstanceOf[String] => println(x.asInstanceOf[String].toUpperCase) case Container(x) if x.isInstanceOf[Double] => println(math.sqrt(x.asInstanceOf[Double])) case _ => println("_") }
이것은 작동하지만, 전혀 우아한 보이지 않는다. 교수 마틴 오더 스키, 스칼라의 창조자는 isInstanceOf 및 asInstanceOf 피해야한다라고 말한다.
롭 노리스 코 세라의 과정 "스칼라 함수 프로그래밍"의 포럼에, 저를 지적한 바와 같이, 유형에 일치하는 것은 잘못된 방법입니다 : 경우 foo는 : 바 => ... 스칼라 정적 타이핑을 활용하고 방지하기 위해 권장 런타임시 유형을 검사합니다. 이 하스켈 / ML 세계의 철학과 일치한다. 대신 유형 일치의 사례 절은 생성자와 일치해야합니다.
컨테이너 매칭 문제를 해결하기 위해, 각 유형에 대한 특별한 용기를 정의 할 수 있습니다 :
class Container[+A](val value: A) case class StringContainer(override val value: String) extends Container(value) case class DoubleContainer(override val value: Double) extends Container(value)
그리고 지금 생성자가 아닌 유형을 일치합니다 :
container match { case StringContainer(x) => println(x.toUpperCase) case DoubleContainer(x) => println(math.sqrt(x)) case _ => println("_") }
분명히, 우리는 두 개체, StringContainer 및 DoubleContainer에 적용 취소 방법을 정의 할 수 있으며, 대신에 컨테이너 클래스를 확장하는, 위와 같은 일치를 사용합니다 :
case class Container[+A](val value: A) object StringContainer { def unapply(c: Container[String]): Option[String] = Some(c.value) } object DoubleContainer { def unapply(c: Container[Double]): Option[Double] = Some(c.value) }
그러나이 때문에 JVM 유형의 삭제에, 다시 작동하지 않습니다.
이 답변에 저를 이끌어 롭 노리스 포스트에 대한 참조는 여기에서 찾을 수 있습니다 : https://class.coursera.org/progfun-002/forum/thread?thread_id=842#post-3567. 당신이 코 세라 코스에 등록하지 않으면 불행하게도, 당신은 그것을 액세스 할 수 없습니다.
-
==============================
4.참고 : (여기에 이미 2012 년 마일 언급) 마일 사빈의 볼품없는 도서관과 대안을 가지고있다.
참고 : (여기에 이미 2012 년 마일 언급) 마일 사빈의 볼품없는 도서관과 대안을 가지고있다.
당신은 자코 Pallari에서 "스칼라의 패턴 일치 일반적인 유형의 방법"의 예를 볼 수 있습니다
import shapeless._ def extractCollection[T: Typeable](a: Any): Option[Iterable[T]] = { val list = TypeCase[List[T]] val set = TypeCase[Set[T]] a match { case list(l) => Some(l) case set(s) => Some(s) case _ => None } } val l1: Any = List(1, 2, 3) val l2: Any = List[Int]() val s: Any = Set(1, 2, 3) extractCollection[Int](l1) // Some(List(1, 2, 3)) extractCollection[Int](s) // Some(Set(1, 2, 3)) extractCollection[String](l1) // None extractCollection[String](s) // None extractCollection[String](l2) // Some(List()) // Shouldn't this be None? We'll get back to this.
from https://stackoverflow.com/questions/16056645/how-to-pattern-match-on-generic-type-in-scala by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 아파치 스파크의 매트릭스 곱셈 [폐쇄] (0) | 2019.11.03 |
---|---|
[SCALA] 아파치 스파크에 null 값을 포함하면 가입 (0) | 2019.11.03 |
[SCALA] 나는 스칼라에 밀봉 부모로부터 파생 케이스의 모든 개체의 컴파일 시간 목록을받을 수 있습니까? (0) | 2019.11.03 |
[SCALA] 어떻게 22 개 필드의 스칼라 경우 클래스의 제한을 극복하기 위해? (0) | 2019.11.03 |
[SCALA] 스칼라 : 어떻게 "일반적인"기능 매개 변수를 정의? (0) | 2019.11.03 |