Scala Case Class Companion Objects - 类型名称冲突

Posted

技术标签:

【中文标题】Scala Case Class Companion Objects - 类型名称冲突【英文标题】:Scala Case Class Companion Objects - Conflict on the type name 【发布时间】:2018-08-10 22:44:39 【问题描述】:

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

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

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

或 jsonFormat3(Class3) 为

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

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

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),它将正常工作。所以,似乎类型是冲突的。

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

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

【问题讨论】:

你的意思是jsonFormat2(Class2.apply) 【参考方案1】:

Class2 的伴生对象被隐式定义时,它扩展(String, Integer) =&gt; Class2;你的版本没有。如果你改成

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

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

【讨论】:

感谢您的回复。我接受了 Tyukin 的回答,因为它提供了更完整的解释。我也赞成你和你的评论。【参考方案2】:

您对object Class2 的定义没有扩展(String, Integer) =&gt; Class2。你可能想明确地传递apply-方法:

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

object Class2 extends DefaultJsonProtocol 

    def getJsonFormat() = 
        jsonFormat2(Class2.apply)
    


受@AlexeyRomanov 有用的评论的启发,我决定添加一个稍微更详细的解释,为什么它在您不定义伴随对象时有效,以及为什么当您将其定义为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,因此符合(?, ?) =&gt; ?

当你自己定义object Foo时,生成的对象不会扩展 (Int, String) =&gt; Foo。这就是为什么当您定义同伴时它会停止工作 无需扩展 Function 即可自行创建对象。

【讨论】:

"如果调用jf2(Foo),它将构造函数Foo作为双参数方法,一切正常。"这是不正确的,它需要伴随对象。 @AlexeyRomanov 确实,你是对的。我认为它会将构造函数自动脱糖到jf2(new Foo(_, _)),但事实并非如此。我撤回了关于构造函数的有缺陷的理论,只保留了(希望有用的)结论。

以上是关于Scala Case Class Companion Objects - 类型名称冲突的主要内容,如果未能解决你的问题,请参考以下文章

Scala class和case class的区别

Scala之Case Class

scala case class

scala-case class

scala中case class与一般的class的区别

scala伴生对象与case class用法