gpt4 book ai didi

scala - 合并案例类的自定义和编译器生成的伴随对象。合并规则是什么?

转载 作者:行者123 更新时间:2023-12-02 15:35:36 26 4
gpt4 key购买 nike

我刚刚尝试了下面的代码,它按预期工作。它打印 1

现在,我的问题是我不明白幕后发生了什么。

一个案例类如何拥有两个伴生对象(一个由编译器生成,一个由我编写)?也许不能。因此,它们必须以某种方式在幕后合并。我只是不明白它们是如何合并的?有什么我应该注意的特殊合并规则吗?

如果两个伴生对象中定义的定义集不相交,那么结果案例类中的定义集是否只是两个不相交集的并集?我认为这就是它们合并的方式,但我不确定。有人可以确认一下这个合并规则是否是在 Scala 编译器中实现的吗?或者还有什么额外的东西吗?

更具体地说,编译器生成的伴生对象和我的伴生对象合并所遵循的规则是什么?这些规则是否在某处指定?

我还没有真正在我读过的几本 Scala 书籍中看到过这个主题的讨论——也许太肤浅了。

object A{
implicit def A2Int(a:A)=a.i1
}
case class A(i1:Int,i2:Int)

object Run extends App{
val a=A(1,2)
val i:Int=a
println(i)
}

最佳答案

我不知道合并自动和显式伴随对象的算法在哪里被描述或记录(除了编译器源代码),但是通过编译代码然后检查生成的伴随对象(使用javap),我们可以看到有什么区别(这是 scala 2.10.4 的情况)。

这是为案例类生成的伴随对象(没有额外的伴随对象):

  Compiled from "zip.sc"
public final class A$ extends scala.runtime.AbstractFunction2<Object, Object, A> implements scala.Serializable {
public static final A$ MODULE$;
public static {};
public A apply(int, int);
public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(A);

public java.lang.Object apply(java.lang.Object, java.lang.Object);
public final java.lang.String toString();
}

添加伴生对象后,生成的内容如下:

  Compiled from "zip.sc"
public final class A$ implements scala.Serializable {
public static final A$ MODULE$;
public static {};
public A apply(int, int);
public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(A);
public int A2Int(A);
}

由显式伴生对象定义引起的生成伴生对象的差异似乎是:

  1. 它不再扩展 AbstractFunction2
  2. 它不再具有与项目符号 1 相关的工厂方法(apply)
  3. 它不再重写 toString 方法(我想您应该在需要时提供一个)
  4. 您的 A2Int 方法已添加

如果案例类更改为普通类(以及编译所需的最小更改),结果如下:

  Compiled from "zip.sc"
public final class A$ {
public static final A$ MODULE$;
public static {};
public A apply(int, int);
public int A2Int(A);
}

因此,如果您声明自己的伴生对象,至少在这个简单的示例中,效果是您的新方法被添加到伴生对象中,并且它的一些实现和功能也丢失了。如果我们尝试覆盖一些剩余的自动生成的内容,看看会发生什么会很有趣,但剩下的东西已经不多了,所以一般来说不太可能引起冲突。

案例类的一些好处与生成的代码无关,例如使类变量公开而无需显式添加“val”关键字。这是上面所有 3 个反编译示例的修改后的源代码。

版本 1(无显式伴生对象):

case class A(i1:Int,i2:Int)

版本 2 是您的原始版本。

版本 3(无案例级别):

object A {
implicit def A2Int(a:A)=a.i1
def apply(a:Int,b:Int):A = new A(a,b)
}
class A(val i1:Int,val i2:Int)

object Run extends App{
import A._
val a=A(1,2)
val i:Int=a
}

在版本 3 中,我们需要将 val 添加到 A 类参数(否则它们是私有(private)的),并且我们必须将工厂方法添加到我们的伴生对象中,或者在创建 A 类实例时使用“new”关键字A(1,2)。

关于scala - 合并案例类的自定义和编译器生成的伴随对象。合并规则是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22760814/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com