如何实现案例类的实例共享

Sil*_*man 5 scala class case-class

假设定义:

case class IntegerWrapper(i : Int)
Run Code Online (Sandbox Code Playgroud)

并且处于可能创建可能具有大量IntegerWrapper实例的情况下,i=[0..N>必须做什么:

  1. 将此范围映射到一组固定的单例 [IntegerWrapper(0) .. IntegerWrapper(N)>

  2. 保留类的现有值语义IntegerWrapper(匹配,等号,哈希码,序列化)

我希望做实例共享类似于什么java.lang.Integer.我想我的问题是,如果可以在不必自己做所有事情的情况下完成.简单地定义一个apply(i : Int)不能编译的伴随对象.有什么建议?

Ste*_*eve 6

如果你只是想避免分配,也许你想要的是一个价值类?在Scala 2.10中,如果您的IntegerWrapper类扩展AnyVal,实例通常不会被分配,而是在值本身上调用静态方法.例如:

scala> case class IntegerWrapper(val i: Int) extends AnyVal { def increment = i + 1 }
defined class IntegerWrapper

scala> object Test { IntegerWrapper(2).increment }
defined module Test

scala> :javap -verbose Test
...    
public Test$();
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #13; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   putstatic   #15; //Field MODULE$:LTest$;
   8:   getstatic   #20; //Field IntegerWrapper$.MODULE$:LIntegerWrapper$;
   11:  iconst_2
   12:  invokevirtual   #24; //Method IntegerWrapper$.extension$increment:(I)I
   15:  pop
   16:  return
Run Code Online (Sandbox Code Playgroud)

请注意,那里调用的扩展方法是Int => Int.

为了比较,如果你不扩展,这是你得到的AnyVal:

scala> :javap -verbose Test
...
public Test$();
  Code:
   Stack=3, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #13; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   putstatic   #15; //Field MODULE$:LTest$;
   8:   new #17; //class IntegerWrapper
   11:  dup
   12:  iconst_2
   13:  invokespecial   #20; //Method IntegerWrapper."<init>":(I)V
   16:  invokevirtual   #24; //Method IntegerWrapper.increment:()I
   19:  pop
   20:  return
Run Code Online (Sandbox Code Playgroud)

使用此版本,您可以查看对象分配以及对新IntegerWrapper实例的方法的调用.


Mal*_*off 2

像这样的东西吗?

sealed trait IntegerWrapper {
  def i: Int
}

object IntegerWrapper extends (Int => IntegerWrapper) {
  private case class IntegerWrapperImpl(i: Int) extends IntegerWrapper

  private val instances: List[IntegerWrapperImpl] = ...
    /* Wrapper instances for i in [0..N) */

  def apply(i: Int): IntegerWrapper = instances(i)

  def unapply(iw: IntegerWrapper): Option[Int] = Some(iw.i)
}
Run Code Online (Sandbox Code Playgroud)

优点是equalshashCode仍然由编译器生成,因为IntegerWrapperImpl是一个案例类。缺点是您不能直接使用其他编译器添加的案例类好东西,例如copy. 如果你想使用它,要么暴露IntegerWrapperImpl给客户端,或者,恕我直言,最好添加copyIntegerWrapper接口中。

模式匹配照常工作:

val iw0 = IntegerWrapper(0)
val iw1: IntegerWrapper = IntegerWrapper(1)

iw0 match {
  case IntegerWrapper(0) => println("IW(0)")
  case _ => println("something else")
} // IW(0)

iw1 match {
  case IntegerWrapper(1) => println("IW(1)")
  case _ => println("something else")
} // IW(1)

iw1 match {
  case IntegerWrapper(2) => println("IW(2)")
  case _ => println("something else")
} // something else
Run Code Online (Sandbox Code Playgroud)