简体   繁体   English

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

[英]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 {包含两个错误:
    1. it has to be extends not with . 它必须是extendswith The latter is only used after you already extended from some base-class/trait. 后者仅在您已从某些基类/特征扩展后使用。
    2. BaseCrud requires a type parameter that you have to specify here, so something like BaseCrud[Customer] BaseCrud需要你必须在这里指定的类型参数,所以类似于BaseCrud[Customer]
  • and finally, to answer your actual question: There is a huge difference between a type parameter 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.

相关问题 创建一个伴随对象,该对象混合了一个特性,该特性定义了一个方法,该方法返回对象的伴随类的对象 - Create a companion object that mixes in a trait that defines a method which returns an object of the object's companion class 使用trait对象中指定的方法的通用内部伴侣对象返回类实例 - Return class instance using generic inside companion object for method specified in trait 伴生对象可以扩展一些与伴生类不同的特征吗? - Can companion object extend some trait different from companion class? 随播对象的类 - Companion object's class 通过给定的通用类型 Scala 获取 class 的同伴 object - Get companion object of class by given generic type Scala 如何在泛型类中引用伴随对象的方法? - How can I reference a companion object's method in a generic class? 需要从案例类的特征中引用同伴对象的特征 - Need to Reference Trait on Companion Object From Trait on Case Class 将案例类的伴随对象用作类型参数时编译错误 - Compile error when using a companion object of a case class as a type parameter 是否有办法创建一个具有trait或mixin的泛型类,它是type参数的子类型 - Is there are way to create a generic class with a trait or mixin that is a subtype of the type parameter Dotty 无法推断具有抽象类型的类型参数特征的泛型 Scala 函数的结果类型 - Dotty cannot infer result type of generic Scala function taking type parameter trait with abstract type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM