Java Scala如何区分()=>;T和=>;T
我的已作为副本关闭,因此我将再试一次。我也读过,我的要求不同。我感兴趣的是学习Java Scala如何区分()=>;T和=>;T,java,scala,Java,Scala,我的已作为副本关闭,因此我将再试一次。我也读过,我的要求不同。我感兴趣的是学习按名称调用:=>Type与()=>Type的内部实现 我的困惑来自于查看javap和反汇编,这两种情况没有任何区别 e、 g.参数测试。scala: object ParamTest { def bar(x: Int, y: => Int) : Int = if (x > 0) y else 10 def baz(x: Int, f: () => Int) : Int = if (x >
按名称调用:=>Type
与()=>Type
的内部实现
我的困惑来自于查看javap和反汇编,这两种情况没有任何区别
e、 g.参数测试。scala:
object ParamTest {
def bar(x: Int, y: => Int) : Int = if (x > 0) y else 10
def baz(x: Int, f: () => Int) : Int = if (x > 0) f() else 20
}
javap输出javap parametest.scala
:
public final class ParamTest {
public static int baz(int, scala.Function0<java.lang.Object>);
public static int bar(int, scala.Function0<java.lang.Object>);
}
编辑1:
Scala语法树:scalac-Xprint:parse parametest.Scala
package <empty> {
object ParamTest extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
def bar(x: Int, y: _root_.scala.<byname>[Int]): Int = if (x.$greater(0))
y
else
10;
def baz(x: Int, f: _root_.scala.Function0[Int]): Int = if (x.$greater(0))
f()
else
20
}
}
包{
对象参数测试扩展了scala.AnyRef{
def()={
超级(;
()
};
定义条(x:Int,y:_root_uu.scala.[Int]):Int=if(x.$greater(0))
Y
其他的
10;
def baz(x:Int,f:_root_u.scala.Function0[Int]):Int=if(x.$greater(0))
f()
其他的
20
}
}
编辑2:邮件列表研究:
object ParamTest {
def bar(x: Int, y: => Int) : Int = if (x > 0) y else 10
def baz(x: Int, f: () => Int) : Int = if (x > 0) f() else 20
}
请阅读邮件列表中的内容,该邮件列表基本上说明=>T
是作为()=>T
实现的。引述:
首先,看看
f:=>Boolean
尽管这被称为“按名称参数”,但它实际上是作为函数0
实现的
f:()=>Boolean
只是两端使用了不同的语法
现在我更困惑的是,哪一个明确地说两者是不同的
问题:
object ParamTest {
def bar(x: Int, y: => Int) : Int = if (x > 0) y else 10
def baz(x: Int, f: () => Int) : Int = if (x > 0) f() else 20
}
- Scala如何将
与条形图
区分开来?在反编译代码中,两者的方法签名(不是实现)是相同的baz
- 这两个场景中的差异是否不会持久化到编译的字节码中李>
- 反编译的代码不准确吗李>
- 在编辑1之后添加:我发现scalac语法树确实显示了差异,
具有类型为bar
的第二个参数。它有什么作用?任何解释、指针或等效伪代码都会有所帮助\u root\u.scala.[Int]
- 参见上面的编辑2:引用的块是否正确?与中一样,
是=>T
的一个特殊子类吗Function0
- Scala代码由编译器分析并转换为jvm字节码。在scala级别,您有隐式、非常强的类型系统、按名称调用参数和其他类似的东西。在字节码中,这一切都消失了。没有curry参数,没有隐式,只有普通方法。运行时不需要区分
()=>A
和=>A
,它只执行字节码。所有检查和验证、错误都来自于分析scala代码的编译器,而不是字节码。在编译过程中,名称只是替换为Function0
,此类参数的所有用法都对其调用了apply
方法,但这不会发生在解析阶段,但稍后,这就是为什么您会在编译器输出中看到
。试着看看后面的阶段
Scala如何将条形图
与baz
区分开来?方法签名(不是
在反编译代码中,这两种方法的实现是相同的
Scala不需要区分这两者。从它的角度来看,这是两种不同的方法。有趣的是(至少对我来说)如果我们将baz
重命名为bar
,并尝试使用“callby name”参数创建重载,我们会得到:
Error:(12, 7) double definition:
method bar:(x: Int, f: () => Int)Int and
method bar:(x: Int, y: => Int)Int at line 10
have same type after erasure: (x: Int, f: Function0)Int
def bar(x: Int, f: () => Int): Int = if (x > 0) f() else 20
这对我们来说是一个暗示,在封面下,对Function0
的翻译正在进行
这两个场景中的差异是否不会持久化到
编译字节码
在Scala发出JVM字节码之前,它还有额外的编译阶段。本例中一个有趣的例子是查看“uncurry”阶段(-Xprint:uncurry
):
[[uncurry结尾的语法树]]
包装测试{
对象参数测试扩展对象{
def():testing.ParamTest.type={
parametest.super.();
()
};
定义条(x:Int,y:()=>Int):Int=if(x.>(0))
y、 应用()
其他的
10;
def baz(x:Int,f:()=>Int):Int=if(x.>(0))
f、 应用()
其他的
20
}
}
甚至在我们发出字节码之前,bar
就被翻译成Function0
反编译的代码不准确吗
不,绝对准确
我发现scalac语法树确实显示了不同,bar有
类型为root.scala.[Int]的第二个参数。这是什么意思
是吗
Scala编译是分阶段完成的,每个阶段的输出都是下一个阶段的输入。除了解析的AST之外,Scala阶段还创建符号,这样,如果一个阶段依赖于特定的实现细节,那么它将具有可用性
是一个编译器符号,它表明此方法使用“按名称调用”,以便其中一个阶段可以看到它并对其进行处理
因为Scala就是这样工作的。它将scala代码编译成.class文件并在JVM中执行。因此.class文件应该具有必要且充分的信息 是的。此信息存储在名为的注释中
javap-v
应该显示它的存在,但它不是人类可读的
这是必要的,因为Scala签名中有很多信息无法在JVM字节码中表示:不仅仅是名称vs
Function0
参数,还有访问限定符、参数名称等。为什么在JVM字节码中表示这些类型很重要?它们在Scala代码中是不同的,重要的是(除非您试图从Java调用Scala,但这不是您要问的),因为Scala就是这样工作的。它将scala代码编译成.class文件并在JVM中执行。因此.class文件应该具有必要且充分的信息。Scala源文件一点都不重要。