Scala:如何在类和伴随对象之间进行继承

Scala:如何在类和伴随对象之间进行继承,scala,Scala,我试图在Scala中设置一个案例类层次结构,它使用伴随对象。每个case类都有一个具有隐式方法的伴生对象,但是,我想创建一个case类可以扩展的抽象类。问题是我没有办法使抽象类的伴生对象也抽象。以下是代码,我目前拥有: abstract class Call {} abstract class ArgumentsCall extends Call {} trait Jsonable[T] { implicit def convert: CodecJson[T] } case

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

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
有人能给我一个很好的方法来解释类/伴生对象以及如何使用它们进行继承吗?我有一种感觉,我对如何实现这一点有一个根本性的误解


感谢

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

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
    可以使用helper trait中混合的乘法
  • 但这并不意味着类AA的实例(即
    valA=newAA
    )将从帮助线程继承!事实上,事实并非如此。它可以继承或混合完全不相关的其他特征

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

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
    可以使用helper trait中混合的乘法
  • 但这并不意味着类AA的实例(即
    valA=newAA
    )将从帮助线程继承!事实上,事实并非如此。它可以继承或混合完全不相关的其他特征

嗨!第一印象是:对于“编译器无法确定ArgumentsCall或其子级将具有隐式def convert:CodecJson”的结论,我会更加小心。我看不出你是如何得出这个结论的,因为实际的编译消息指向另一个方向:看起来编译器不能创建方法体,因为它找不到casecodec2的第二个参数列表中使用的隐式值——这意味着,定义隐式方法是不相关的,因为编译器受到了在方法体中使用的隐式值的限制。两者都是“隐含的”,这纯粹是巧合。至少这是我在阅读此编译器消息时的直觉。作为一般规则,您应该尝试将内容分解为更小、更易于管理的部分。虽然这是一个通用的“干净代码规则”,但这在Scala中尤其重要,因为事情可能会很快变得非常复杂。在您的例子中,您试图将三件事打包到一个定义系统中:(1)结构数据类型(case类)。(2) 隐式转换。(3) 编解码器的具体选择。因此,我会立即将这三个分开。使用特征混合隐式转换。这种隐式转换只是委托一种实现方法来选择正确的编解码器。然后,这种实现方法可以在结构数据类型(案例类)上使用模式匹配。这样你就可以让每一点单独工作。嗨!第一印象是:对于“编译器无法确定ArgumentsCall或其子级将具有隐式def convert:CodecJson”的结论,我会更加小心。我看不出你是如何得出这个结论的,因为实际的编译消息指向另一个方向:看起来编译器不能创建方法体,因为它找不到casecodec2的第二个参数列表中使用的隐式值——这意味着,定义隐式方法是不相关的,因为编译器受到了在方法体中使用的隐式值的限制。两者都是“隐含的”,这纯粹是巧合。至少这是我在阅读此编译器消息时的直觉。作为一般规则,您应该尝试将内容分解为更小、更易于管理的部分。虽然这是一个通用的“干净代码规则”,但这在Scala中尤其重要,因为事情可能会很快变得非常复杂。在您的例子中,您试图将三件事打包到一个定义系统中:(1)结构数据类型(case类)。(2) 隐式转换。(3) 编解码器的具体选择。因此,我会立即将这三个分开。使用特征混合隐式转换。这种隐式转换只是委托一种实现方法来选择正确的编解码器。然后,这种实现方法可以在结构数据类型(案例类)上使用模式匹配。这样你就可以把每一点都分开工作了。伊希约,如果我没听错的话。您的意思是,首先,我应该将所有隐式方法移到一个trait中,并将它们混合在一起。从那以后,删除对象是否有意义,因为我可以将trait混合到case类中?还是我遗漏了什么。谢谢你的回复。可能。。。但我不确定我是否准确地理解了你想要实现的目标。既然您正在定义隐式方法,我猜您正在寻找一些案例类实例的自动创建,对吗?但是如果是这样,那么您只需要一个隐式方法,但是这个隐式方法需要一个参数,并且您需要一些方法来从这个参数中找出要实例化的case类