简体   繁体   English

Scala - 如何在运行时保证val不变性

[英]Scala - How is val immutability guaranteed at run time

When we create a final in java it is guaranteed that it cannot be changed even at run time because the JVM guarantees it. 当我们在java中创建final时,保证即使在运行时也无法更改它,因为JVM保证它。

Java class: Java类:

public class JustATest {
    public final int x = 10;
}

Javap decompiled: Javap反编译:

Compiled from "JustATest.java" 编译自“JustATest.java”

public class JustATest {
  public final int x;

  public JustATest();
    Code:
       0: aload_0
       1: invokespecial #1                // Method java/lang/Object."<init>":()V
       4: aload_0
       5: bipush        10
       7: putfield      #2                  // Field x:I
      10: return
}

But in scala, if we declare a val , it compiles into a normal integer and there is no difference between var and val in terms of decompilation output. 但是在scala中,如果我们声明一个val ,它会编译成一个普通的整数,并且就反编译输出而言var和val之间没有区别。

Original Scala class: 原始Scala类:

class AnTest {

  val x = 1
  var y = 2
}

Decompiled output: 反编译输出:

Compiled from "AnTest.scala"
public class AnTest {
  public int x();
    Code:
       0: aload_0
       1: getfield      #14                 // Field x:I
       4: ireturn

  public int y();
    Code:
       0: aload_0
       1: getfield      #18                 // Field y:I
       4: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #18                 // Field y:I
       5: return

  public AnTest();
    Code:
       0: aload_0
       1: invokespecial #25                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_1
       6: putfield      #14                 // Field x:I
       9: aload_0
      10: iconst_2
      11: putfield      #18                 // Field y:I
      14: return
}

With that information, the concept of immutability of a val is controlled only at compile time by the scala compiler? 有了这些信息, val的不变性概念仅在编译时由scala编译器控制? How is this guaranteed at run time? 如何在运行时保证这一点?

In Scala, conveying immutability via val is a compile time enforcement which has nothing to do with the emitted byte code. 在Scala中,通过val传递不变性是一种编译时执行 ,它与发出的字节代码无关。 In Java, you state that when the field is final in order for it not to be reassigned, where in Scala, declaring a variable with val only means it can't be reassigned, but it can be overridden. 在Java中,您声明当字段为final ,为了不重新分配,在Scala中,仅使用val声明变量意味着它不能被重新分配,但可以覆盖它。 If you want a field to be final , you'll need to specify it as you do in Java: 如果你想要一个字段是final ,你需要像在Java中那样指定它:

class AnTest {
  final val x = 10
}

Which yields: 产量:

public class testing.ReadingFile$AnTest$1 {
  private final int x;

  public final int x();
    Code:
       0: bipush        10
       2: ireturn

  public testing.ReadingFile$AnTest$1();
    Code:
       0: aload_0
       1: invokespecial #19                 // Method java/lang/Object."<init>":()V
       4: return
}

Which is equivalent to the byte code you see in Java, except the compiler has emitted a getter for x . 这相当于您在Java中看到的字节代码,除了编译器为x发出了一个getter。

The really simple answer is: there are some Scala features which can be encoded in JVM bytecode, and some which can't. 真正简单的答案是:有一些Scala功能可以用JVM字节码编码,有些则不能。

In particular, there are some constraints which cannot be encoded in JVM bytecode, eg sealed or private[this] , or val . 特别是,存在一些不能在JVM字节码中编码的约束 ,例如sealedprivate[this]val Which means that if you get your hands on the compiled JVM bytecode of a Scala source file, then you can do stuff that you can't do from Scala by interacting with the code through a language that is not Scala. 这意味着如果你掌握了Scala源文件的已编译JVM字节码,那么你可以通过非Scala语言与代码交互来完成Scala无法做到的事情。

This is not specific to the JVM backend, you have similar, and even more pronounced problems with Scala.js, since the compilation target here (ECMAScript) offers even less ways of expressing constraints than JVM bytecode does. 这不是JVM后端特有的,你在Scala.js方面有类似甚至更明显的问题,因为这里的编译目标(ECMAScript)提供了比JVM字节码更少的表达约束的方法。

But really, this is just a general problem: I can take a language as safe and pure as Haskell, compile it to native code, and if I get my hands on the compiled binary, all safety will be lost. 但实际上,这只是一个普遍的问题:我可以使用像Haskell一样安全和纯粹的语言,将其编译为本机代码,如果我接受编译后的二进制文件,所有安全性都将丢失。 In fact, most Haskell compilers perform (almost) complete type erasure, so there are literally no types, and no type constraints left after compilation. 实际上,大多数Haskell编译器执行(几乎)完全类型擦除,因此实际上没有类型,并且编译后没有类型约束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM