【发布时间】:2016-11-08 15:23:02
【问题描述】:
假设我有以下功能:
case class ErrA(msg: String)
case class ErrB(msg: String)
def doA(): Either[ErrA, Int] = Right(2)
def doB(): Either[ErrB, Int] = Right(3)
ErrA 和 ErrB 是不相关的类型,实际上并未在本示例之外的同一文件中声明。它们不能轻易地从通用类型继承。
我想介绍一种新类型,它可以代表两种错误类型:
sealed trait ErrAOrB
case class ErrAWrapper(e: ErrA) extends ErrAOrB
case class ErrBWrapper(e: ErrB) extends ErrAOrB
然后使用 for 推导式编写以下函数:
def doAplusB(): Either[ErrAOrB, Int] =
for (a <- doA().right;
b <- doB().right) yield a + b
有没有办法让编译器将那些特定的Either 类型隐式转换为常见的Either[ErrAOrB, Int] 类型?
例如:
implicit def wrapA[T](res: Either[ErrA, T]): Either[ErrAOrB, T] = res.left.map(ErrAWrapper(_))
implicit def wrapB[T](res: Either[ErrB, T]): Either[ErrAOrB, T] = res.left.map(ErrBWrapper(_))
但这不起作用,因为隐式转换仅应用于 for 理解中的最终表达式,然后编译器必须将其绑定到 doA 并且由于类型 ErrA 和 ErrAOrB 不相关最好的办法是使泛型有意义是使用与预期类型不兼容的Object。
【问题讨论】:
-
只是要注意在 Scala 中不推荐使用隐式视图 - 使用隐式类代替,所以它可能类似于
doA().right.wrap。想象一下人们阅读您的代码并想知道Either[ErrA, Int]是如何变成ErrAOrB的?没有 IDE 提示,所以没有找到你的wrapAimplicits 的好方法
标签: scala monads implicit-conversion for-comprehension implicits