在Scala中,是否可以使用包含与字段名称相同的方法的案例类?

时间:2012-08-24 06:41:41

标签: scala

我想我希望能够做类似下面的事情(显然是垃圾)代码说明:

// Clearly nonsensical
case class Example(a: String) {
    def a: Array[Byte] = a.getBytes
}

它的要点是我想为一个案例类编写一个访问器方法,该案例类的命名与其构造函数的一个参数相同。

我正在使用名为Jerkson的JSON序列化库,根据我的理解,如果我以这种方式定义类,它将以我想要的方式运行。我基于this code的假设。目前,我stumped

如果无法做到这一点,是否有人能够对杰克逊图书馆代码试图做些什么提供一些见解?

2 个答案:

答案 0 :(得分:3)

不,这是不可能的。原因是case类的构造函数参数是自动公共值,就像使用val声明它们一样。引用A Tour of Scala: Case Classes

  

案例类的构造函数参数被视为公共值,可以直接访问。

因此,对于每个构造函数参数,Scala会创建一个具有相同名称的相应accessor method。你不能创建一个具有相同名称的方法,它已经存在。

这实际上是case类的内容。我们的想法是它们可以用于模式匹配,因此从它们检索的值应该与用于构造它们的值相同。

(是否要求使用case类?使用常规类似乎可以解决问题。)

答案 1 :(得分:3)

Scala会自动创建一个与类中声明的val同名的方法(包括案例类的字段),以支持名为referential transparency的概念。这也是override a def with a val的原因。如果你仍然持怀疑态度,你可以自己测试一下:

首先,创建一个包含单个案例类的Scala文件。

// MyCase.scala
case class MyCase(myField1: Int, myField2: String)

现在,使用scalac编译文件。这应该导致两个类。对于上面的示例,我得到 MyCase.class (表示实际的案例类类型)和 MyCase $ .class (表示案例类的自动生成的伴随对象)。

$ scalac MyCase.scala 
$ ls
MyCase$.class MyCase.class  MyCase.scala

现在,您可以检查与使用.class声明的案例类对应的结果javap文件。 (javap标准工具,用于检查Java字节码 - 它与JDK中的javac一起分发。)

$ javap -private MyCase
Compiled from "MyCase.scala"
public class MyCase extends java.lang.Object implements scala.Product,scala.Serializable{
    private final int myField1;
    private final java.lang.String myField2;
    public static final scala.Function1 tupled();
    public static final scala.Function1 curry();
    public static final scala.Function1 curried();
    public scala.collection.Iterator productIterator();
    public scala.collection.Iterator productElements();
    public int myField1();
    public java.lang.String myField2();
    public MyCase copy(int, java.lang.String);
    public java.lang.String copy$default$2();
    public int copy$default$1();
    public int hashCode();
    public java.lang.String toString();
    public boolean equals(java.lang.Object);
    public java.lang.String productPrefix();
    public int productArity();
    public java.lang.Object productElement(int);
    public boolean canEqual(java.lang.Object);
    private final boolean gd1$1(int, java.lang.String);
    public MyCase(int, java.lang.String);
}

请注意结果类如何同时具有与案例类private final int myField1字段对应的public int myField1()myField1myField2也一样。

在JVM方法上,返回类型是不是方法签名的一部分。这意味着如果两个方法具有相同的名称和相同的参数类型,那么它们被认为是冲突的方法声明。这意味着您无法在示例中声明def a: Array[Byte],因为val a: String已经存在,也没有参数。

更新

我只是查看了库代码,根据示例,case类应该正常工作。 README中的一条注释,说解析案例类在REPL中不起作用。这可能是你的问题吗?如果没有,你应该发布你得到的错误。 修改:没关系,我看到您在链接到其他帖子时所说的错误。如果我想到对这个问题的回应,我会在那里发布。