[英]generic trait taking a class and it's companion object as a type parameter
So I want to have a generic trait take as a type parameter a class with a companion object that inherits from a specific base class and refer to both the companion object and the class itself. 所以我希望将一个通用特征作为一个类型参数,一个具有从特定基类继承的伴随对象的类,并引用伴随对象和类本身。 So,
所以,
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)
}
I had some solutions to that trait that were closer but I distilled it down so you can see what I am trying to do. 我有一些解决方案,这个特性更接近,但我把它提炼下来,这样你就可以看到我想要做的事情。
Thanks 谢谢
UPDATE UPDATE
So I went with solution from Frank below, but I did manage to solve my initial puzzle. 所以我选择了Frank下面的解决方案,但我确实设法解决了我最初的难题。 Though, in this case the solution was a bit ugly I'll include it here for completeness sake.
虽然,在这种情况下,解决方案有点难看,但为了完整起见,我会将其包含在这里。
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)
}
So the type parameters changed to BaseCrud and the implicit was added to BaseCrud.table and implemented in Controller.model. 因此,类型参数更改为BaseCrud,并将隐式添加到BaseCrud.table并在Controller.model中实现。 I also fixed all my typos.
我也解决了所有错别字。 I found it interesting Customer.type seems to be the type of the companion object.
我觉得有趣的是Customer.type似乎是伴侣对象的类型。
There's a bunch of problems in your code.. let's tackle it one after the other: 你的代码中有很多问题......让我们一个接一个地解决它:
def table[T](...
note that this T
overwrites the original type parameter for the scope of the method. Not what you want really, so just omit it and make this def table(...
def table[T](...
请注意,这个T
覆盖方法范围的原始类型参数。不是你想要的,所以只需省略它并制作这个def table(...
object Controller with BaseCrud {
contains two more mistakes: object Controller with BaseCrud {
包含两个错误:
extends
not with
. extends
不with
。 The latter is only used after you already extended from some base-class/trait. BaseCrud
requires a type parameter that you have to specify here, so something like BaseCrud[Customer]
BaseCrud
需要你必须在这里指定的类型参数,所以类似于BaseCrud[Customer]
T
and a companion object . T
和伴随对象之间存在巨大差异。 They are inherently different things, so you cannot access the companion object via T.something
. T.something
访问伴随对象。 Instead you need to provide the companion object in your trait in some other way, for example as an abstract field. Here's a version of what I believe you want to do: 这是我认为你想做的一个版本:
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)
}
I think, you can use scala self
type in BaseCrud
trait to specify a class it should be mixed in. See linked question for details. 我认为,您可以在
BaseCrud
特征中使用scala self
类型来指定它应该混合的类。有关详细信息,请参阅链接的问题 。
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)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.