Scala案例类伴随对象 - 类型名称

时间:2018-03-02 17:00:24

标签: scala types spray-json companion-object

我遇到了Companion Objects选择其类型而不是案例类

的问题

我正在使用喷雾json serdes。他们需要一个隐式的JsonFormat。这种格式是通过调用依赖于case类的参数数量的函数获得的:如果case类有两个字段,则为jsonFormat2(Class2),如

case class Class2(a: String, b: Integer)

的jsonFormat3(Class3)
case class Class3(a: String, b: Integer, c: Long)

鉴于必须知道你的case类在整个代码中的params数量并不好,我想创建一个case类的伴随对象,这样你就可以封装这个信息并从类本身获取JsonFormat,如: / p>

object Class2 extends DefaultJsonProtocol 
{
    def getJsonFormat() = {
        jsonFormat2(Class2)
    }
}

但如果我这样做,我将得到以下编译问题:

type mismatch;
[error]  found   : mypackage.Class2.type
[error]  required: (?, ?) => ?
[error]     jsonFormat2(Class2)

如果我们查看jsonFormat2中的代码,签名是:

def jsonFormat2[P1 :JF, P2 :JF, T <: Product :ClassManifest
    (construct: (P1, P2) => T): RootJsonFormat[T] = { // ... 

如果我更改伴随对象名称(例如,更改为MyClass2),它将起作用。所以,似乎类型是冲突的。

似乎在处理打字时,伴侣对象将无法像他们所使用的类一样被命名。

有人可以解释为什么会发生这种情况,如果有限制,或者如何处理它,那么伴侣对象可以使用相同的名称吗?

2 个答案:

答案 0 :(得分:4)

当隐式定义Class2的伴随对象时,它会扩展(String, Integer) => Class2;你的版本没有。如果您改为

object Class2 extends DefaultJsonProtocol with (String, Integer) => Class2 { ... }

它会起作用,但为了避免重复参数类型,我会选择Andrey Tyukin的建议(即使解释不正确)。

答案 1 :(得分:2)

您对object Class2的定义不会延伸(String, Integer) => Class2。您可能希望明确传递apply - 方法:

case class Class2(a: String, b: Integer)

object Class2 extends DefaultJsonProtocol 
{
    def getJsonFormat() = {
        jsonFormat2(Class2.apply)
    }
}

受到@ AlexeyRomanov的有用评论的启发,我决定添加一个稍微更详细的解释,为什么当你没有定义一个伴随对象时它起作用,以及当你将它定义为{{{}时它停止工作的原因1}}。

如果你编译

object Class2 { ... }

然后自动生成的伴随对象的反编译代码如下所示:

class Foo(n: Int, s: String)

即,它扩展了public final class Foo$ extends AbstractFunction2<Object, String, Foo> implements Serializable { /* some lines omitted */ public Foo apply(int n, String s) { return new Foo(n, s); } /* some lines omitted */ } ,因此符合AbstractFunction2

当您自己定义(?, ?) => ?时,生成的对象不会延伸 object Foo。这就是定义伴侣时停止工作的原因 对象不依赖(Int, String) => Foo