gpt4 book ai didi

scala - 为什么隐式值类有一个额外的方法调用?

转载 作者:行者123 更新时间:2023-12-01 13:39:07 24 4
gpt4 key购买 nike

我正在检查由隐式类生成的字节码,并想与它们扩展 AnyVal 时生成的内容进行比较。

没有隐式:

object Example1 {
class Wrapper(val self: Int) extends AnyVal {
def add(n: Int): Int = self + n
}
def foo(w: Wrapper): Wrapper = new Wrapper(w.add(42))
}

字节码(的相关部分):

scala>:javap Example1

[...]

public int foo(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: getstatic #19 // Field Example1$Wrapper$.MODULE$:LExample1$Wrapper$;
3: iload_1
4: bipush 42
6: invokevirtual #23 // Method Example1$Wrapper$.add$extension:(II)I
9: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this LExample1$;
0 10 1 w I
LineNumberTable:
line 11: 3

[...]

使用隐式:

object Example2 {
implicit class Wrapper(val self: Int) extends AnyVal {
def add(n: Int): Int = self + n
}
def foo(w: Wrapper): Wrapper = w.add(42)
}

字节码(的相关部分):

scala>:javap Example2

[...]

public int Wrapper(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: iload_1
1: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this LExample2$;
0 2 1 self I
LineNumberTable:
line 9: 0

public int foo(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
0: aload_0
1: getstatic #23 // Field Example2$Wrapper$.MODULE$:LExample2$Wrapper$;
4: iload_1
5: bipush 42
7: invokevirtual #27 // Method Example2$Wrapper$.add$extension:(II)I
10: invokevirtual #29 // Method Wrapper:(I)I
13: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this LExample2$;
0 14 1 w I
LineNumberTable:
line 12: 0

[...]

作为扩展 AnyVal 的结果,对伴生对象调用了 addWrapper 类型不显示在两个版本中 foo 的类型签名 (public int foo(int);)。

但是,在第二个版本中,在返回之前有一个调用:10: invokevirtual #29。它调用 public int Wrapper(int); 似乎什么也没做。 (虽然我可能是错的,因为我没有太多阅读字节码的经验)

那么问题来了,这个调用的意义是什么?不能省略吗?

最佳答案

问题是您的代码片段不等价。隐式类 Foo 被编译/脱糖为类 Foo 隐式转换方法 Foo。这也是隐式类(目前)不能成为顶级的原因。

所以你的第一个片段应该是:

object Example1 {
class Wrapper(val self: Int) extends AnyVal {
def add(n: Int): Int = self + n
}
def Wrapper(self: Int): Wrapper = new Wrapper(self)
def foo(w: Wrapper): Wrapper = Wrapper(w.add(42))
}

如果可能,编译器会删除对值类构造函数的调用。但它不会删除对 Wrapper 方法 的调用,无论是否是隐式的。

我猜 JVM 中的 JIT 编译器最终会清除该方法调用。

关于scala - 为什么隐式值类有一个额外的方法调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41814411/

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