类型相关类型

时间:2017-08-04 06:44:49

标签: scala

我们说我们有以下特点:

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.MyBooleanU必须为String。每次TMyValue.MyLong时,U必须为Double。换句话说,TU之间存在一种基础映射。

有没有一种使用类型类的好方法?

1 个答案:

答案 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之外的其他东西,你将收到一个错误。