복붙노트

[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. ==============================

    1.일반 rarry의 대답에서 컨테이너는 제네릭 형식의 단일 값을 포함하고 있기 때문에 귀하의 경우에, 그러나 그것은, 단순화 할 수있다, 그래서 당신이 직접 그 값의 유형에 일치시킬 수 있습니다, 올바른 :

    일반 rarry의 대답에서 컨테이너는 제네릭 형식의 단일 값을 포함하고 있기 때문에 귀하의 경우에, 그러나 그것은, 단순화 할 수있다, 그래서 당신이 직접 그 값의 유형에 일치시킬 수 있습니다, 올바른 :

    container match {
      case Container(x: String) => println("string")
      case Container(x: Double) => println("double")
      case _ => println("w00t")
    }
    
  2. ==============================

    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. ==============================

    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. ==============================

    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.
    
  5. from https://stackoverflow.com/questions/16056645/how-to-pattern-match-on-generic-type-in-scala by cc-by-sa and MIT license