Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Scala如何区分()=>;T和=>;T_Java_Scala - Fatal编程技术网

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>);
}
编辑1Scala语法树
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源文件一点都不重要。