斯卡拉.具有一个字段的案例类可以是值类吗?

Ale*_*var 30 scala scala-2.10

Scala 2.10引入了值类.它们对于编写类型安全代码非常有用.此外还有一些限制,其中一些将由编译器检测,有些则需要在运行时进行分配.

我想使用case class语法创建值类,以允许创建 - 无需新语法和人性化toString.没有模式匹配,因为它需要分配.

所以问题是:将使用case class语法需要值类分配吗?

Rüd*_*ehn 34

您可以拥有一个值类的案例类.从下面的示例中可以看出,没有对象创建.除了当然不可避免的拳击,如果你会向上倾向任何.

这是一小段scala代码

class ValueClass(val value:Int) extends AnyVal

case class ValueCaseClass(value:Int) extends AnyVal

class ValueClassTest {

  var x: ValueClass = new ValueClass(1)

  var y: ValueCaseClass = ValueCaseClass(2)

  def m1(x:ValueClass) = x.value

  def m2(x:ValueCaseClass) = x.value
}
Run Code Online (Sandbox Code Playgroud)

字节码,不包含两个值类的最轻微的痕迹.

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

  public void x_$eq(int);
    Code:
       0: aload_0       
       1: iload_1       
       2: putfield      #14                 // Field x:I
       5: return        

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

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

  public int m1(int);
    Code:
       0: iload_1       
       1: ireturn       

  public int m2(int);
    Code:
       0: iload_1       
       1: ireturn       

  public rklaehn.ValueClassTest();
    Code:
       0: aload_0       
       1: invokespecial #29                 // 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      #21                 // Field y:I
      14: return        
}
Run Code Online (Sandbox Code Playgroud)

  • 大多数人可能知道这一点,但它可能仍然有用.您可以在`AnyVal`案例类上进行模式匹配,但随后将强制进行对象分配.小心你的假设(检查字节码,分析你的应用程序,并使用编译器wanring标志,以确保你得到的是你想要的). (3认同)

Von*_*onC 7

为了扩展这个问题,Wojciech Langiewicz提出了一个用作案例类的Value类的一个很好的例子.

代替:

case class Player(id: Int, gameCash: Int, gameCoins: Int, energy: Int)
Run Code Online (Sandbox Code Playgroud)

Wojciech定义:

case class Player(id: PlayerId, gameCash: GameCash, gameCoins: GameCoins, energy: Energy)
Run Code Online (Sandbox Code Playgroud)

使用case类(不在堆上分配其他对象):

case class PlayerId(id: Int) extends AnyVal
case class GameCash(value: Int) extends AnyVal
case class GameCoins(value: Int) extends AnyVal
case class Energy(value: Int) extends AnyVal
Run Code Online (Sandbox Code Playgroud)

在创建只包含一个参数的case类时,你应该添加它extends AnyVal以允许Scala编译器运行更多优化 - 基本上类型检查只在编译阶段完成,但在运行时只会创建底层类型的对象,这会导致更少的内存开销.

在我们的代码中的特定点添加自定义类型不仅提高了可读性,而且还允许我们减少错误 - 卸载一些检查,否则这些检查必须在测试中完成(或者根本不需要).您还可以立即在IDE或编辑器中看到错误.

因为现在类中的每个组件Player本身都是一个单独的类型,所以添加新的操作符也很容易,否则可能必须隐式添加这些操作符会污染更大的范围.