簡體   English   中英

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

[英]Type mismatch on abstract type used in pattern matching

此代碼編譯時出現錯誤:

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
}

在模式匹配表達式中的兩種情況下,我們都知道ibIntBoolean 為什么第一個示例編譯失敗而第二個示例編譯成功?

第一種情況是不合理的,因為您低估了 Scala 類型系統中類型的多樣性。 它將使意義,如果當我們把case i:Int分支,我們知道TInt ,或至少的超類型Int 但它不一定是! 例如,它可以是42.type標記類型

在第二種情況下沒有這樣的問題,因為從IntExpr <: Expr[T] ,編譯器確實知道T必須正好是Int

你要求你的函數返回一個類型T ,然后你對IntBoolean模式匹配。 除了您的函數沒有證據表明IntBoolean也是T類型:當您進行模式匹配時, 您引入了Int <: TBoolean <: T 的約束 您可以將返回類型T替換為固定類型(如String並返回一個 String ,或者引入一個同時滿足IntBoolean情況的約束。

//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因為你需要在編譯時證明你的函數類型檢出。

您示例中的另一個函數通過在案例類IntExpr <: Expr[Int]BoolExpr <: Expr[Boolean]封裝類型約束來避免該問題(注意Expr[_]在我上面提到的約束中如何等效於T )。 在編譯時, T 在所有case都被正確識別(例如,在IntExpr知道它是Int

除了@Esardes 的回答之外,這還通過為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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM