scala类型参数作为对象类型

时间:2016-07-31 16:51:20

标签: scala inheritance typeclass value-class

我怎样才能做到这一点:

final case class ChairId(id: String)

trait GeneratorLike[TO, TC <: AbstractId] {
  val prefix: String
  def generate(): TC = TO.apply(prefix + "-" + UUID.randomUUID())
}

implicit object ChairIdGenerator extends GeneratorLike[ChairId.type, ChairId] {
  val prefix: String = "CHAIR"
}

implicit def IdFn[TO, TC <: AbstractId](x: TO)(implicit ev: GeneratorLike[TO, TC]): GeneratorLike[TO, TC] = ev

//right now I can call:
ChairId.generate()

我不想为那种情况定义伴侣对象,我想知道是否有机会使用implicits来扩展对象?

当我这样做时(我使用TO作为TypeObject和TC作为TypeClass命名)idFn[TO, TC]我希望TO成为实现def apply(id: String): TC的对象我可以强制执行吗?我将如何使用此功能?在类型参数上调用函数是完全不可能的:/

2 个答案:

答案 0 :(得分:2)

无法在类型参数上调用方法,因为它代表类型而不是对象。您可以在对象上调用方法,因为它是存在的东西,但类型是抽象概念。我不知道你想要隐含地将generate()添加到伴侣对象的动机是什么,因为它实际上需要定义隐式GeneratorLike的代码与定义{ChairId的伴侣一样多。 1}}。

如果你强制GeneratorLike拥有apply方法(可以通过案例类apply实现),并删除第一个类型参数,这将有效。

trait GeneratorLike[TC <: AbstractId] { this: Singleton =>
  val prefix: String
  def apply(id: String): TC
  def generate(): TC = apply(prefix + "-" + UUID.randomUUID())
}

abstract class AbstractId

final case class ChairId(id: String) extends AbstractId

object ChairId extends GeneratorLike[ChairId] {
  val prefix = "CHAIR"
}

scala> ChairId.generate()
res0: ChairId = ChairId(CHAIR-60bb01c7-af95-46c7-af45-0b3fa78b3080)

答案 1 :(得分:0)

结构类型在JVM上并不是一个特别好的主意,因此总是尽量避免使用def test(x: {def apply(s: String)}): TC类型的东西,因为它是使用反射实现的,这可能是一种性能明智的狗。

其次,您应该避免在val内使用trait。阅读here

您考虑的方法实际上是正确的方法,即类型类。

trait HasGenerator[T] {
  def apply(uuid: String): T 
  def generate[T : Generator] = apply(Generator[T].generate)
}

final case class ChairId(id: String) 

object ChairId extends HasGenerator[ChairId]

trait Generator[TO] {
  def prefix: String
  def generate(): String = prefix + "-" + UUID.randomUUID()
  def apply(): String = generate
}

object Generator {
  def apply[T : Generator] = implicitly[Generator[T]]
}

// Notice .type is not necessary
implicit object ChairIdGenerator extends Generator[ChairId] {
  override def prefix = "CHAIR"
}

为什么不使用:

ChairId(Generator[ChairId])

这一切看起来都有些过分,所以你可以很容易地以某种方式。值得更多地满足您的要求是值得的,因为类型类似乎还不是非常必要。你可以这样做:

<强>更新

如果你使用我上面添加的HasGenerator之类的东西与伴侣对象一起使用,你现在可以成功呼叫ChairId.generate()