通用特征取一个类,它的伴随对象作为类型参数

时间:2012-05-09 07:55:23

标签: scala generics

所以我希望将一个通用特征作为一个类型参数,一个具有从特定基类继承的伴随对象的类,并引用伴随对象和类本身。所以,

abstract class BaseModel[T] {
  def all: Seq[T]
}

case class Customer(email: String, password: String)

object Customer extends BaseModel[Customer]

// This trait is my issue
trait BaseCrud[T] { 
  def table[T](f: T => String): String = {
    T.all.map(f _).mkString("")
  }
}

object Controller with BaseCrud {
  def foo = table(_.email)
}

我有一些解决方案,这个特性更接近但我把它提炼下来所以你可以看到我想要做的事情。

由于

更新

所以我选择了弗兰克的解决方案,但我确实设法解决了我最初的难题。虽然,在这种情况下,解决方案有点难看,但为了完整起见,我会把它包含在这里。

abstract class BaseModel[T] {
  def all: Seq[T] = Seq()
}

case class Customer(email: String, password: String)

object Customer extends BaseModel[Customer]

trait BaseCrud[T, U <: BaseModel[T]] { 
  def table(f: T => String)(implicit obj: U): String = {
    obj.all.map(f(_)).mkString("")
  }
}

object Controller extends BaseCrud[Customer, Customer.type] {
  implicit val model = Customer
  def foo = table(_.email)
}

因此类型参数更改为BaseCrud,并将隐式添加到BaseCrud.table并在Controller.model中实现。我也解决了所有错别字。我发现它很有趣Customer.type似乎是伴随对象的类型。

2 个答案:

答案 0 :(得分:7)

您的代码中存在许多问题。让我们一个接一个地解决它:

  • def table[T](...请注意,此T会覆盖方法范围的原始类型参数。不是你想要的,所以只需省略它并制作def table(...
  • object Controller with BaseCrud {还包含两个错误:
    1. 必须是extends而不是with。后者仅在您已从某些基类/特征扩展后才使用。
    2. BaseCrud需要您必须在此处指定的类型参数,例如BaseCrud[Customer]
  • 最后,回答您的实际问题:类型参数T和随播对象之间存在巨大差异。它们本质上是不同的东西,因此您无法通过T.something访问配套对象。相反,您需要以某种其他方式在特征中提供伴随对象,例如作为抽象字段。

以下是我认为你想要做的一个版本:

abstract class BaseModel[T] {
  def all: Seq[T]
}

case class Customer(email: String, password: String)

object Customer extends BaseModel[Customer] {
  def all = List[Customer]() // have to define this
}

trait BaseCrud[T] {
  val companion : BaseModel[T]
  def table(f: T => String): String = {
    companion.all.map(f).mkString("")
  }
}

object Controller extends BaseCrud[Customer] {
  val companion = Customer
  def foo = table(_.email)
}

答案 1 :(得分:2)

我认为,您可以在self特征中使用scala BaseCrud类型来指定应该混合的类。有关详细信息,请参阅linked question

trait BaseCrud[T] {
  self: BaseModel[T] =>
  def table(f: T => String): String =
    all.map(f).mkString("")
}

object Controller extends BaseModel[Customer] with BaseCrud[Customer]{
  def foo = table(_.email)
}