如何修复此折叠示例中的类型推断错误?

时间:2015-04-12 08:23:13

标签: scala type-inference

假设我正在写作:

sealed trait Status
object Error1 extends Status
case class Ok(x: Int) extends Status  

def foo(opt: Option[Int]): Status = opt.fold(Error1)(x => Ok(x))

当我在REPL中尝试时,我收到错误:

scala> def foo(opt: Option[Int]): Status = opt.fold(Error1)(x => Ok(x))
<console>:11: error: type mismatch;
found   : Ok
required: Error1.type
   def foo(opt: Option[Int]): Status = opt.fold(Error1)(x => Ok(x))
                                                               ^

我可以解决它,但看起来不是特别优雅:

 // work around the type error above
 val error1: Status = Error1
 def ok(x: Int): Status = Ok(x)

 def foo(opt: Option[Int]): Status = opt.fold(error1)(x => ok(x))

您如何建议解决此类问题?

4 个答案:

答案 0 :(得分:6)

如您所见fold从第一个arg提供的零/回退值推断返回类型。它是Error因为它解决了最具体的值类型。

您可以通过以下方式注释折叠,以表明您需要Status

opt.fold[Status](err)(x => Ok(x))
opt.fold(err: Status)(x => Ok(x))

答案 1 :(得分:3)

编译器推断出类型是Error1,因为这是传递给fold的第一个参数的类型。

就直接问题的答案而言,您可以告诉编译器它是一个Error1,但相关类型是Status,通过明确地将类型作为Status传递

sealed trait Status
object Error1 extends Status
case class Ok(x: Int) extends Status  

def foo(opt: Option[Int]): Status = opt.fold(Error1: Status)(x => Ok(x))

然后函数foo将返回如下:

scala> foo(Option(5))
res0: Status = Ok(5)

答案 2 :(得分:3)

折叠签名如下:

final def fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B

因此,它是一个带有类型参数B的curried函数。所以它首先执行opt.fold(Error1)并推断B是Error1。因此,第二部分(x => Ok(x))应为(f: (A) => Error1),因此编译器会抱怨。

您可以使用以下类型明确修复它:

scala> def foo(opt: Option[Int]): Status = opt.fold[Status](Error1)(x => Ok(x))
foo: (opt: Option[Int])Status

答案 3 :(得分:2)

除了其他答案,您还可以使用模式匹配:

opt match { case None => Error1; case Some(x) => Ok(x) }

因为在这种情况下,编译器 使用来自两个分支的类型信息,并将在Error1Ok(x)之间寻找一个公共类型。