我有一个容器类型,用于保存与值相关联的元数据。
class Container[A](val value: Option[A], val meta: Metadata)
有时访问元是有用的,但大多数时候使用值更方便,就好像Option[A]
一样。有一个隐含的转换。
object Container {
implicit def containerToValue[A](c: Container[A]): Option[A] = c.value
}
所有这一切都很好。问题是,A => B
通常会出现隐式转化,而且值恰好是Container[A]
。我要做的是提供一种基本上从Container[A] => Option[B]
进行隐式转换的方法。我的第一次尝试是有效的:
object Container {
implicit def containerToValue[A](c: Container[A]): Option[A] = c.value
implicit def containerToB[A,B](c: Container[A])(implicit conv: (A) => B): Option[B] = c.value.map(conv)
}
Scala完全不喜欢这样,所以作为一个后备,因为90%的案例B
实际上都是String
,我尝试用更多填写的类型做一些事情:
object Container {
implicit def containerToValue[A](c: Container[A]): Option[A] = c.value
implicit def containerToB[A](c: Container[A])(implicit conv: (A) => String): Option[String] = c.value.map(conv)
}
这样做有点好,但是我有很多关于歧义的错误。我想知道的是,是否有办法指定A
不是String
。也许是这样的事情:
implicit def containerToB[A >!> String]
这样我就可以告诉编译器这种隐式转换仅在A不是String时适用。
有没有更好的方法来解决这个问题?
答案 0 :(得分:1)
而不是进行隐式转换(因为它们难以调试,在您最不期望它们时导致运行时错误,并且使代码通常不太清楚)为什么不在混合中添加类型类以便您可以使用你希望与他们合作的方式?
trait Extractor[A,B]{
def opt(that: Container[A]): B
}
然后显式创建您可能想要的所有各种实例:
def myGloriousFunction[B](that: Container[A])(implicit ex: Extractor[A,B]) ={
val value = ex.opt(that)
//more stuff
}
它将处理内部Option
的“提取器”的发现,并且它的签名仍然相当明确。