【问题标题】:Scala dynamic dispatch with parameterized function具有参数化函数的 Scala 动态调度
【发布时间】:2016-02-26 23:52:26
【问题描述】:

如何使这段代码工作?

据我所知,Scala 没有动态调度(类似于 Java)。是否可以以某种方式模拟动态调度?

或者最好的解决方案是什么?

object Tezt {

  case class SuperClazz()
  case class SubClazz1() extends SuperClazz
  case class SubClazz2() extends SuperClazz

  def method(obj: SubClazz1) = {
    // stuff
  }

  def method(obj: SubClazz2) = {
    // stuff
  }

  def func[T <: SuperClazz](obj: T) = {
    Tezt.method(obj) // Error: Cannot resolve method reference with such signature
  }
}

【问题讨论】:

  • java 也不允许这样做。您的代码完全错误。试着用文字解释你想要做什么。
  • 我说Java也没有。我有一个接收对象的函数,它是SuperClazz 的子类,并且有 2 个方法,每个子类都有 onde。我怎么知道要找到哪个?
  • 假设,这是允许的。如果你传入一个 Subclazz3 的实例,然后呢?

标签: scala types type-inference dynamic-dispatch multiple-dispatch


【解决方案1】:

在单个参数上实现动态调度的标准方法是面向对象的多态性:

abstract class SuperClazz() {
  def method(): ReturnType
}
case class SubClazz1() extends SuperClazz {
  def method() = {
    // stuff
  }
}
case class SubClazz2() extends SuperClazz {
  def method() = {
    // stuff
  }
}

// Alternatively just `def func(obj: SuperClazz) =` in this case
def func[T <: SuperClazz](obj: T) = 
  obj.method()

请注意,您不能用另一个case class 扩展case class,而且扩展case classes 通常被认为是不好的风格。要实现这一点,您可能需要将method 抽象为SuperClazz,因此SuperClazz 应该是traitabstract class

scala 中动态调度的另一种常见替代方法是模式匹配:

sealed abstract class SuperClazz()
case class SubClazz1() extends SuperClazz
case class SubClazz2() extends SuperClazz

def method(obj: SubClazz1) = {
  // stuff
}

def method(obj: SubClazz2) = {
  // stuff
}

def func(obj: SuperClazz) =
  obj match {
    case sc1: SubClazz1 => method(sc1)
    case sc2: SubClazz2 => method(sc2)
  }

当超类或特征是sealed(在本例中为sealed abstract class SuperClazz())时,通常会像这样实现模式匹配。当匹配密封超类的对象时,编译器会检查你是否列出了匹配中的所有可能性,以确保匹配时不会出现运行时错误。如果您忘记指定某些可能性,编译器会给您一个警告。

模式匹配也适用于多参数动态分派,但与多态性相比,它们通常需要编写更多样板代码,并且在线性测试每个匹配案例和调用unapply 函数时可能需要更高的运行时性能成本。

【讨论】:

  • 旁注:我不能从另一个案例类扩展一个案例类?不确定,但我这样做没有任何错误。顺便说一句,为什么扩展案例类被认为是不好的做法?
  • @pedrorijo91 案例类到案例类继承自 scala 2.9 版以来已被禁止。您是否尝试使用这种继承编译一些代码? IDE 可能不会给出错误,但它仍然无法在现代 scala 版本中编译。
  • @pedrorijo91 至于从案例类继承普通类,通常是没有意义的。所有自动案例类方法仍将由父案例类提供。例如,在子节点上调用 copy 方法会返回父案例类的实例。未覆盖的 equalshashCode 仅考虑存在于父案例类中的字段。并且没有针对孩子的apply/unapply 的自动伴随对象。通常的方法是有一些特征和抽象类的层次结构,并且只使这个继承层次结构中的叶子为case classes。
猜你喜欢
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
  • 1970-01-01
  • 2018-02-02
  • 2014-02-27
  • 2021-08-31
  • 1970-01-01
  • 2017-09-28
相关资源
最近更新 更多