如何访问作为类型参数传递的Scala类的伴随对象?

如何访问作为类型参数传递的Scala类的伴随对象?,scala,generics,companion-object,Scala,Generics,Companion Object,我有一个带有伴生对象的case类: 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[Chee

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

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 = ???

如何访问晚餐子类的companion对象?

您可能希望从标准集合库的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
现在,晚餐的每个实例都有方法companion,而companion又有IngCreditName


EDIT added printMenu与伴生对象无关,它将object Taco和object CheeseBurger用作普通的typeclass实例。

您可能希望以下构造受到标准集合库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
现在,晚餐的每个实例都有方法companion,而companion又有IngCreditName


EDIT added printMenu与伴生对象无关,它将对象Taco和对象CheeseBurger用作普通的typeclass实例。

要拯救的类型类:

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

键入要救援的类别:

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

为什么同伴反对塔可延长晚餐[塔可]?这不应该,因为案例类Taco已经扩展了晚餐[Taco],我想这是一个打字错误吧?不可能有两个不同的类使用不同的算术进行晚餐。@Andrey-我相信object和case类都可以这样扩展晚餐,因为晚餐的算术为零。正当然而,我并不是说这是个好主意。不,晚餐[Taco]需要算术1,而晚餐需要算术0。它们不能在同一范围内共存。@Andreytukin您指的是printMenu部分吗?那应该是D不,我指的是塔科班的晚餐。它仍然有arity 0。应该是类Taco延长晚餐[Taco]。为什么同伴对象Taco延长晚餐[Taco]?这不应该,因为案例类Taco已经扩展了晚餐[Taco],我想这是一个打字错误吧?不可能有两个不同的类使用不同的算术进行晚餐。@Andrey-我相信object和case类都可以这样扩展晚餐,因为晚餐的算术为零。正当然而,我并不是说这是个好主意。不,晚餐[Taco]需要算术1,而晚餐需要算术0。它们不能在同一范围内共存。@Andreytukin您指的是printMenu部分吗?那应该是D不,我指的是塔科班的晚餐。它仍然有arity 0。这应该是塔可延长晚餐的课程[Taco]。这很好,让我走到了一半——但是,在我找到同伴之前,它仍然需要我有一个晚餐的例子。我的目标是在不实际拥有Taco实例的情况下访问Taco.ingredientNames,而只是将类型Taco作为类型参数传递。例如,printMenu[D@Sasgorilla添加了printMenu。它现在不依赖于任何其他对象的伴生对象,因此我不确定您为什么要在问题中添加所有的肉/奶酪/酱/面包和所有其他东西。您的printMenu需要称为printMenu[Taco.type]或printMenuTaco,而不是printMenu[Taco].虽然这是可以解决的。@AlexeyRomanov是的,你是对的,解决了。在没有太多思考的情况下附加了最后一种方法,我认为问题的重点完全是在别的东西上。太多的玉米卷了。这太好了,让我走到了一半——但是,我仍然需要吃一顿饭才能找到同伴。我的目标是是在没有Taco实例的情况下访问Taco.ingredientNames,只是将类型Taco作为类型参数传递。例如,printMenu[D@Sasgorilla添加了printMenu。它现在不依赖于任何其他对象的伴生对象,所以我不知道你为什么要在问题中添加所有的肉/奶酪/酱/面包和所有其他东西。你的printMenu需要称为printMenu[Taco.type]或printMenuTaco,而不是printMenu[Taco].虽然这是可以解决的。@AlexeyRomanov是的,你是对的,解决了。在没有太多思考的情况下附加了最后一种方法,我认为问题的重点完全在其他方面。太多的玉米卷了。