假设我正在写作:
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))
您如何建议解决此类问题?
答案 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) }
因为在这种情况下,编译器 使用来自两个分支的类型信息,并将在Error1
和Ok(x)
之间寻找一个公共类型。