我们说我们有以下特点:
trait MyValue
object MyValue {
case class MyBoolean(record: Boolean) extends MyValue
case class MyLong(record: Long) extends MyValue
}
trait MyValueExtractor[T] {
def apply(record: T): Option[MyValue]
}
trait MyThing[T] {
def name: String
def myValueExtractor: MyValueExtractor[T]
def myValue(record: T): Option[MyValue] = myValueExtractor(record)
}
我想要的是这样的,但没有第二个类型参数。
注意:我实际上无法更新MyThing
特征;我只是将其用作预期功能的说明。
trait MyThing[T, U] {
def name: String
def myValueExtractor: MyValueExtractor[T]
def myValue(record: T): Option[MyValue] = myValueExtractor(record)
def myRelatedValue(record: T): Option[U]
}
我想知道我是否可以使用类型类模式来帮助解决这个问题(即,导入一些隐含地给我myRelatedValue
方法的富类?)
这就是问题所在。 每次 T
(上方)为MyValue.MyBoolean
,U
必须为String
。每次T
为MyValue.MyLong
时,U
必须为Double
。换句话说,T
和U
之间存在一种基础映射。
有没有一种使用类型类的好方法?
答案 0 :(得分:2)
不确定。您只需要定义一些Mapping
类型类,其中包含所需类型对的实现。然后MyThing
可以有一个方法,它接受一个隐式类型类实例,只是调用它的方法。
这是代码(我删除了不需要的细节)
// types
case class MyBoolean(record: Boolean)
case class MyLong(record: Long)
// trait which uses the Mapping typeclass
trait MyThing[T] {
def myRelatedValue[U](record: T)(implicit ev: Mapping[T, U]): Option[U] = ev.relatedValue(record)
}
// typeclass itself
trait Mapping[T, U] {
def relatedValue(record: T): Option[U]
}
object Mapping {
implicit val boolStringMapping = new Mapping[MyBoolean, String] {
def relatedValue(record: MyBoolean) = Some(record.record.toString)
}
implicit val longDoubleMapping = new Mapping[MyLong, Double] {
def relatedValue(record: MyLong) = Some(record.record)
}
}
// usage
val myBoolThing = new MyThing[MyBoolean] {}
val myLongThing = new MyThing[MyLong] {}
val myStringThing = new MyThing[String] {}
myBoolThing.myRelatedValue(MyBoolean(true)) // Some(true)
myLongThing.myRelatedValue(MyLong(42L)) // Some(42.0)
myStringThing.myRelatedValue("someString") // error: could not find implicit value
请注意,例如myBoolThing.myRelatedValue(MyBoolean(true))
将生成Option[U]
类型。但是,由于myRelatedValue
已参数化,您可以帮助编译器并将其作为myBoolThing.myRelatedValue[String](MyBoolean(true))
调用,在这种情况下,您将获得Option[String]
。如果你为MyBoolean尝试除String之外的其他东西,你将收到一个错误。