代码之家  ›  专栏  ›  技术社区  ›  Bogdan Vakulenko

模式匹配中使用的抽象类型的类型不匹配

  •  9
  • Bogdan Vakulenko  · 技术社区  · 8 年前

    此代码编译时出错:

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

    sealed trait Expr[T]
    case class IntExpr(i: Int) extends Expr[Int]
    case class BoolExpr(b: Boolean) extends Expr[Boolean]
    
    def eval[T](e: Expr[T]): T = e match {
      case IntExpr(i) => i
      case BoolExpr(b) => b
    }
    

    在这两种情况下,在模式匹配表达式中我们都知道 是 内景 布尔值 . 为什么第一个例子编译失败,第二个例子编译成功?

    3 回复  |  直到 8 年前
        1
  •  6
  •   Alexey Romanov    8 年前

    第一种情况是不合理的,因为您低估了Scala类型系统中类型的多样性。如果我们在 case i:Int 我们知道的分支 T Int ,或者至少是 . 但不一定是这样!它可能是 42.type 或者 tagged type .

    在第二种情况下没有这样的问题,因为 IntExpr <: Expr[T] ,编译器 做 知道 T型 一定是真的 内景 .

        2
  •  2
  •   John K    6 年前

    T ,那么你的模式匹配 Int 和 Boolean . 内景 和 布尔值 T型 :模式匹配时, you introduce the constraint 那个 Int <: T 和 Boolean <: T . 您可以替换返回类型 String 并返回一个字符串,或引入一个满足这两种情况的约束 内景 布尔值

    //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
    }
    

    基本上你不能只返回任何类型 T型

    示例中的另一个函数通过在case类中封装类型约束来避免这个问题 IntExpr <: Expr[Int] BoolExpr <: Expr[Boolean] (注意 Expr[_] 相当于 T型 在我上面提到的约束中)。在编译时,T在所有 case s(例如 IntExpr 你 知道 这是一个 )

        3
  •  1
  •   airudah    8 年前

    除了@esardesanswer之外,它还通过定义一个绑定到 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
    
    推荐文章