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

Scala 模式匹配中使用的抽象类型上的类型不匹配,scala,generics,Scala,Generics,此代码编译时出错: 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 ... 从类型检查的角度来看,实现GADT的代码看起来非常相同,但编译时没有错误: sealed trait Exp

此代码编译时出错:

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 ...
从类型检查的角度来看,实现GADT的代码看起来非常相同,但编译时没有错误:

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
}

在模式匹配表达式内部的两种情况下,我们都知道ibInt布尔值。为什么编译在第一个示例中失败,在第二个示例中成功

要求函数返回类型
T
,然后根据
Int
Boolean
进行模式匹配。
除非您的函数没有证据表明
Int
Boolean
也属于
T
类型:当您进行模式匹配时,
Int除了@Esardes answer之外,还定义了
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

第一种情况是不合理的,因为您低估了Scala类型系统中类型的多样性。如果我们在处理
案例i:Int
分支时知道
T
Int
,或者至少是
Int
的一个超类型,这是有意义的。但也不一定是这样!例如,它可能是一个或一个


在第二种情况下没有这样的问题,因为我从
IntExpr中删除了我的答案(它是错误的)。我还发现,如果从示例中删除显式返回类型,它将编译并运行。如果是
C++
pre
C++17
(有编译时泛型,但没有编译时
If
),我会告诉你方法体对于任何类型
T
都是不正确的,因为
T
永远不会同时是
Int
Boolean
@bobah,这是因为它可以推断出任何值的返回类型。你的函数就是
def f1[T](e:T)=e
。如果您想要一个解决方案,上下文将很有帮助。也许你只是想要一个why@JoelBerkeley这个问题主要是理论性的,而不是实践性的。我试图理解编译逻辑。这似乎取决于模式是值模式还是类型模式。这也会失败
案例类Expr[T](v:T);def eval[T](e:Expr[T]):T=e匹配{case Expr(i:Int)=>i;case Expr(b:Boolean)=>b}
他匹配
e
,类型为
T
。考虑问题中的第二个例子,<代码>实例INTEXPR(i)=i < /C> >编译,而<代码>实例i:int=> 不。问题是“你的函数没有证据”有什么区别?你的意思是编译器不能计算出来吗?毕竟,在匹配案例中,证据是存在的(当然,也许您需要与
案例e=>e
进行彻底匹配)。使用Any.Int调用f1时必须丢失类型检查,这将是一个遗憾。布尔值有一个公共超类型,即
AnyVal
。编译器可以推断
T
AnyVal
@joel是,问题在于函数的返回类型。我试图为您的问题提供一个解决方案。@fusion如果这样做了,任何时候您有类型问题,它都会退回到AnyVal:我希望类型能够尽早捕获错误,但不确定这是否有帮助
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