0

我怎样才能做到这一点:

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()

我不想为这种情况定义伴随对象,我想知道是否有机会使用隐式扩展对象?

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

4

2 回答 2

2

不可能在类型参数上调用方法,因为它表示的是类型不是对象。您可以在对象上调用方法,因为它是存在的,但类型是一个抽象概念。我不知道您想要隐式添加generate()到伴生对象的动机是什么,因为实际上定义隐式对象所需的代码与GeneratorLikeChairId.

如果您强制GeneratorLike拥有一个apply方法(可以通过 case class 实现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)
于 2016-07-31T17:29:16.550 回答
0

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

其次,您可能应该避免valtrait. 在这里阅读。

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

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()

于 2016-07-31T19:49:46.167 回答