Type mismatch on abstract type used in pattern matching

前端 未结 3 1187
夕颜
夕颜 2020-12-03 11:25

This code compiles with an error:

def f1[T](e: T): T = e match {
  case i:Int => i
  case b:Boolean => b
}
// type mismatch;
// found   : i.type (with          


        
相关标签:
3条回答
  • 2020-12-03 12:05

    You ask of your function to return a type T, then you pattern-match against Int and Boolean. Except your function has no evidence that Int and Boolean are also of type T: when you pattern-match, you introduce the constraint that Int <: T and Boolean <: T. You could either replace the return type T by a fixed type like String and return a String, or introduce a constraint that will satisfy both the case Int and Boolean.

    //this compiles
    def f1[T](e: T ): String = e match {
      case _:Int => "integer"
      case _:Boolean => "boolean"
    }
    
    //this compiles too, but will return AnyVal
    def f1[T >: AnyVal](e: T ): T = e match {
       case i:Int => i
       case b:Boolean => b
    }
    

    Basically you can't just return any type T dynamically because you need to prove at compile time that your function type-checks out.

    The other function in your example avoids the issue by encapsulating type constraints within case classes IntExpr <: Expr[Int] and BoolExpr <: Expr[Boolean] (notice how Expr[_] would be the equivalent of T in the constraints I mentioned above). At compile time, T is properly identified in all cases (e.g in the IntExpr you know it's an Int)

    0 讨论(0)
  • 2020-12-03 12:16

    The first case is unsound because you underestimate the variety of types in Scala type system. It would make sense if, when we took case i:Int branch we knew T was Int, or at least a supertype of Int. But it doesn't have to be! E.g. it could be 42.type or a tagged type.

    There's no such problem in the second case, because from IntExpr <: Expr[T], the compiler does know T must be exactly Int.

    0 讨论(0)
  • 2020-12-03 12:29

    In addition to @Esardes answer, this worked by defining a type bound for T:

    scala> def f1[T >: AnyVal](e: T):T = e match {
         |   case i:Int => i
         |   case b:Boolean => b
         | }
    f1: [T >: AnyVal](e: T)T
    
    scala> f1(1)
    res3: AnyVal = 1
    
    scala> f1(true)
    res4: AnyVal = true
    
    0 讨论(0)
提交回复
热议问题