【问题标题】:How can I access the companion object of a Scala class passed as a type param?如何访问作为类型参数传递的 Scala 类的伴随对象?
【发布时间】:2018-06-01 08:02:08
【问题描述】:

我有一个带有伴生对象的案例类:

object Taco extends Dinner[Taco] {
  def ingredientNames: Seq[String] = Seq("filling", "cheese", "sauce")
}

case class Taco(filling: Meat, cheese: Cheese, sauce: Sauce) 
extends Dinner

还有一个:

object Cheeseburger extends Dinner[Cheeseburger] {
  def ingredientNames: Seq[String] = Seq("cheese", "bun", "condiments")
}

case class CheeseBurger(cheese: Cheese, bun: Bun, condiments: Seq[Condiment]) 
extends Dinner[Cheeseburger]

在实际创建任何晚餐实例之前,我需要获取这些晚餐的成分名称:

def printMenu[D <: Dinner[D]]: String = ???

如何访问Dinner 子类的伴随对象?

【问题讨论】:

  • 为什么伴随对象Taco扩展Dinner[Taco]?这不应该是,因为案例类Taco 已经扩展了Dinner[Taco](我想这是一个错字?不能有两个不同的类Dinner 具有不同的arities)。
  • @Andrey - 我相信对象和案例类都可以像这样扩展Dinner,因为Dinner 的数量为零。 (对吗?)但是,我实际上并不是说这是个好主意。
  • 不,Dinner[Taco] 需要 1,而 Dinner 需要 0。它们不能在同一范围内共存。
  • @AndreyTyukin 你指的是printMenu 部分吗?那应该是D &lt;: Dinner[D]——刚刚编辑以解决这个问题。希望我们同意 Dinner 现在总是有 arity 1。(假设 type 参数被认为是 arity 的一部分,我想一定是这种情况。但也许我误解了你所说的 arity 的意思。)跨度>
  • 不,我提到了class Taco extends Dinner。它仍然有 0。应该是class Taco extends Dinner[Taco]

标签: scala generics companion-object


【解决方案1】:

键入类来拯救:

trait Dinner { ... }
trait DinnerCompanion[A <: Dinner] {
  implicit def self: DinnerCompanion[A] = this
  def ingredientNames: Seq[String]
  ...
}

object Taco extends DinnerCompanion[Taco] {
  def ingredientNames: Seq[String] = Seq("filling", "cheese", "sauce")
}

case class Taco(filling: Meat, cheese: Cheese, sauce: Sauce) extends Dinner

def printMenu[A <: Dinner](implicit companion: DinnerCompanion[A]): String = 
  companion.ingredientNames.mkString(", ")

【讨论】:

    【解决方案2】:

    您可能想要以下构造(灵感来自标准集合库中的GenericCompanion):

    type Condiment = String
    type Meat = String
    type Cheese = String
    type Sauce = String
    type Bun = String
    
    
    trait Dinner[A] {
      def companion: DinnerCompanion[A]
    }
    
    trait DinnerCompanion[A] {
      def ingredientNames: Seq[String]
    }
    
    case class Taco(filling: Meat, cheese: Cheese, sauce: Sauce) 
    extends Dinner[Taco] {
      def companion = Taco
    }
    
    implicit object Taco extends DinnerCompanion[Taco] {
      def ingredientNames: Seq[String] = Seq("filling", "cheese", "sauce")
    }
    
    case class CheeseBurger(cheese: Cheese, bun: Bun, condiments: Seq[Condiment]) 
    extends Dinner[CheeseBurger] {
      def companion = CheeseBurger
    }
    
    implicit object CheeseBurger extends DinnerCompanion[CheeseBurger] {
      def ingredientNames: Seq[String] = Seq("cheese", "bun", "condiments")
    }
    
    def printMenu[D: DinnerCompanion]: String = 
      implicitly[DinnerCompanion[D]].ingredientNames.mkString
    

    现在Dinner 的每个实例都有companion 方法,而companion 又拥有ingredientNames

    EDIT 添加了printMenu(与伴生对象无关,使用object Tacoobject CheeseBurger 作为普通类型类实例)。

    【讨论】:

    • 这很棒,让我走到了一半——但是,它仍然需要我有一个 Dinner 的实例,然后我才能找到同伴。我的目标是在实际上没有 Taco 实例的情况下到达 Taco.ingredientNames,只需将类型 Taco 作为类型参数传递。例如,printMenu[D &lt;: Dinner].
    • @Sasgorilla 添加了printMenu。它现在不以任何方式依赖于任何东西作为其他任何东西的伴侣对象,所以我不确定你为什么在你的问题中添加了所有的肉/奶酪/酱汁/小圆面包和所有其他东西。
    • 您的printMenu 需要被称为printMenu[Taco.type](或printMenu(Taco)),而不是printMenu[Taco]。虽然这可以解决。
    • @AlexeyRomanov 是的,你是对的,已修复。没有多想就附加了最后一种方法,我认为问题的重点完全是在别的东西上。炸玉米饼太多了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 2016-12-05
    • 2013-06-05
    • 2016-08-24
    • 2017-01-08
    相关资源
    最近更新 更多