Scala Case 类伴随对象 - 类型名称冲突

xma*_*mar 5 types scala spray-json companion-object

我遇到了伴随对象选择其类型而不是案例类的问题

我正在使用喷雾 json serdes。他们需要一个隐式的 JsonFormat。此格式是通过调用取决于案例类参数数量的函数来获得的: jsonFormat2(Class2) 如果案例类有两个字段,例如

case class Class2(a: String, b: Integer)
Run Code Online (Sandbox Code Playgroud)

或 jsonFormat3(Class3) 的

case class Class3(a: String, b: Integer, c: Long)
Run Code Online (Sandbox Code Playgroud)

鉴于必须知道案例类在整个代码中具有的参数数量并不好,我想创建一个案例类伴随对象,以便您可以封装此信息并从类本身获取 JsonFormat,例如:

object Class2 extends DefaultJsonProtocol 
{
    def getJsonFormat() = {
        jsonFormat2(Class2)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

type mismatch;
[error]  found   : mypackage.Class2.type
[error]  required: (?, ?) => ?
[error]     jsonFormat2(Class2)
Run Code Online (Sandbox Code Playgroud)

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

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

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

似乎在处理类型时,伴生对象无法像它们所使用的类那样命名。

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

Ale*_*nov 5

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

object Class2 extends DefaultJsonProtocol with (String, Integer) => Class2 { ... }
Run Code Online (Sandbox Code Playgroud)

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


And*_*kin 4

您的定义object Class2不扩展(String, Integer) => Class2. 您可能想apply显式传递 - 方法:

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

object Class2 extends DefaultJsonProtocol 
{
    def getJsonFormat() = {
        jsonFormat2(Class2.apply)
    }
}
Run Code Online (Sandbox Code Playgroud)

受到 @AlexeyRomanov 有用评论的启发,我决定添加一个稍微更详细的解释,为什么它在您没有定义伴生对象时起作用,以及为什么当您将其定义为object Class2 { ... }.

如果你编译

class Foo(n: Int, s: String)
Run Code Online (Sandbox Code Playgroud)

那么自动生成的伴生对象的反编译代码如下所示:

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 */
}
Run Code Online (Sandbox Code Playgroud)

也就是说,它延伸AbstractFunction2,因此符合(?, ?) => ?

object Foo当您自己 定义时,生成的对象不会扩展(Int, String) => Foo。这就是为什么当您自己定义伴生对象而不扩展 时它会停止工作的原因Function

  • “如果您调用 jf2(Foo),它会将构造函数 Foo 作为双参数方法,一切都很好。” 这是不正确的,它需要伴随对象。 (2认同)