【问题标题】:Scala: How can I do inheritance between classes and companion objectsScala:如何在类和伴随对象之间进行继承
【发布时间】:2013-07-11 13:40:21
【问题描述】:

我正在尝试在 Scala 中设置一个使用伴随对象的案例类层次结构。每个案例类都有一个带有隐式方法的伴生对象,但是,我想创建一个案例类可以扩展的抽象类。问题是我无法使抽象类的伴生对象也抽象。下面是代码,我目前有:

abstract class Call {}

abstract class ArgumentsCall extends Call {}

trait Jsonable[T] {
        implicit def convert: CodecJson[T]
}
case class VersionCall(version:String) extends Call  //{"version": "0.1"}
object VersionCall {
        implicit def convert: CodecJson[VersionCall] = casecodec1(VersionCall.apply, VersionCall.unapply)("version")
}

case class CommandCall(command:String,arguments:ArgumentsCall) extends Call //{"command": "pcap-file", "arguments": {"output-dir": "/opt/suricata_out/1", "filename": "/opt/suricata_fifo/1"}}
object CommandCall {
        implicit def convert: CodecJson[CommandCall] = casecodec2(CommandCall.apply, CommandCall.unapply)("command","arguments")
}
case class PcapCall(outputDir:String,filename:String) extends ArgumentsCall
object PcapCall extends ArgumentsCall {
        implicit def convert: CodecJson[PcapCall] = casecodec2(PcapCall.apply, PcapCall.unapply)("output-dir","filename")
}

case class Response(returnS:String, message:Option[String])
object Response {
        implicit def convert: CodecJson[Response] = casecodec2(Response.apply, Response.unapply)("return","message")
}

编译器无法确定 ArgumentsCall 或其子项是否具有“隐式 def convert:CodecJson”。 这是实际的编译器错误:

[error] /blah/src/main/scala/helpers/JsonApi.scala:24: could not find implicit value for evidence parameter of type argonaut.EncodeJson[helpers.ArgumentsCall]
[error]     implicit def convert: CodecJson[CommandCall] = casecodec2(CommandCall.apply, CommandCall.unapply)("command","arguments")
[error]                                                                                                      ^
[error] one error found
[error] (compile:compile) Compilation failed

谁能给我一个很好的方法来推理类/伴随对象以及如何使用它们进行继承?我有一种感觉,我对如何实现这一点有一个根本的误解。

谢谢

【问题讨论】:

  • 嗨!作为第一印象:对于“编译器无法确定 ArgumentsCall 或其子项将具有隐式 def convert:CodecJson”的结论,我会更加小心。我看不出你是如何得出这个结论的,因为实际的编译消息指向另一个方向:看起来编译器无法创建方法体,因为它无法找到第二个参数中使用的隐式值casecodec2列表
  • - 这意味着,您将要定义一个隐式方法是无关紧要的,因为编译器对方法体中使用的隐式值进行了微调。两者都是“隐含的”纯属巧合。至少这是我在阅读此编译器消息时的直觉
  • 作为一般规则,您应该尝试将事物分解为更小且更易于管理的部分。虽然这是一个通用的“干净代码规则”,但在 Scala 中这一点尤其重要,因为事情很快就会变得非常复杂。
  • 在你的例子中,你试图将三样东西打包到一个单一的定义系统中:(1)一个结构数据类型(案例类)。 (2) 隐式转换。 (3)编解码器的具体选择。
  • 因此我会立即将这三个分开。使用特征混合隐式转换。这种隐式转换只是委托给一个实现方法来选择正确的编解码器。然后这个实现方法可以在结构数据类型(案例类)上使用模式匹配。这样你就可以让每一位单独工作。

标签: scala


【解决方案1】:

继承层次结构和伴随对象是两个完全不同的问题。该类及其伴生对象仅共享一个命名空间。事实上,伴生对象可以从完全不相关的事物中继承,它可以混合特征等。

trait Helper {
  def multiply(n:Int) = n*2
}

object AA extends Helper {
    private def fun(i:Int) = multiply(i)
}

class AA {
   def doubleFun(jj:Int) = AA.fun(jj)
}

注意以下事项

  • 成员函数doubleFun可以使用伴生对象的私有函数
  • fun 方法可以使用从辅助 trait 中混入的乘法
  • 但这并不意味着AA类的实例(即val a = new AA)将从Helper线程继承!事实上,事实并非如此。它可以继承或混合完全不相关的其他特征

【讨论】:

  • Ichthyo,如果我没看错的话。您是说首先,我应该将所有隐式方法移动到一个特征并将它们混合在一起。从那里取消对象是否有意义,因为我可以将特征混合到案例类中?或者我错过了什么。感谢您的精彩回复。
  • 可能...但我不确定我是否准确地弄清楚了您想要实现的目标。由于您正在定义隐式方法,我猜您正在寻找一些自动创建案例类实例的方法,对吗?但是如果是这样,那么你只需要一个隐式方法,但是这个隐式方法需要带一个参数,并且你需要一些方法来从这个参数中找出要实例化的案例类。
  • 当您想要自动覆盖时,执行此转换的隐式方法只需要在范围内即可。因此,它可以在封闭(外部)类/对象/特征中定义。或者您可以将其导入当前范围。或者您可以在目标类型的伴随对象中定义它。但是有一个关键要求:在任何需要自动转换的情况下,编译器必须能够找到一种且只有一种可能的隐式方法来应用给定的参数类型。
  • 这篇博文有详细解释...tomjefferys.blogspot.de/2011/11/…
  • Ichthyo,你的建议很有帮助。我按照您的建议结束了使用特征,然后让对象扩展了该特征。感谢您的周到回复!
猜你喜欢
  • 2016-08-09
  • 1970-01-01
  • 2018-02-06
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-01
相关资源
最近更新 更多