5

定義を仮定すると:

case class IntegerWrapper(i : Int)

潜在的に大量のIntegerWrapperインスタンスi=[0..N>が作成される可能性がある状況にある場合、次のことを行う必要があります。

  1. この範囲をシングルトンの固定セットにマップします[IntegerWrapper(0) .. IntegerWrapper(N)>

  2. クラスの既存の値のセマンティクスを維持するIntegerWrapper(マッチング、イコール、ハッシュコード、シリアライゼーション)

私は何と同じようにインスタンス共有を行うことを目指していますjava.lang.Integer。私の質問は、自分ですべてを行う必要なく、これを実行できるかどうかだと思います。コンパニオン オブジェクトを で定義するだけでapply(i : Int)はコンパイルされません。助言がありますか?

4

4 に答える 4

6

割り当てを回避しようとしているだけなら、おそらく値クラスが必要ですか? Scala 2.10 では、IntegerWrapperクラスが extendsAnyValの場合、通常はインスタンスが割り当てられず、代わりに静的メソッドが値自体で呼び出されます。例えば:

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

そこで呼び出される拡張メソッドは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

このバージョンでは、オブジェクトの割り当てと、新しいIntegerWrapperインスタンスのメソッドの呼び出しの両方を確認できます。

于 2012-11-05T13:18:58.203 に答える
4

結果をメモ!Scala を使用すると、必要なすべてのロジックを抽象化することさえできます。

必要なインフラストラクチャ:

scala> :paste
// Entering paste mode (ctrl-D to finish)

// A little memoization utility

object Memoization extends Memoization

trait Memoization {
  trait Memoizable[A] {
    def memoize(fun: A): A
  }

  implicit def fun1memoizable[A, B] = new Memoizable[A => B] {
    def memoize(f: A => B): (A => B) = new MemoizedFunction(f)
  }

  implicit def fun2memoizable[A, B, C] = new Memoizable[(A, B) => C] {
    def memoize(f: (A, B) => C): (A, B) => C = {
      val memo = new MemoizedFunction(f.tupled)
      (a, b) => memo((a, b))
    }
  }

  implicit def fun3memoizable[A, B, C, D] = new Memoizable[(A, B, C) => D] {
    def memoize(f: (A, B, C) => D): (A, B, C) => D = {
      val memo = new MemoizedFunction(f.tupled)
      (a, b, c) => memo((a, b, c))
    }
  }

  def memoize[F](f: F)(implicit m: Memoizable[F]): F = m memoize f

  class MemoizedFunction[-A, +B](f: A => B) extends (A => B) {
    private[this] val cache = collection.mutable.Map.empty[A, B]
    def apply(a: A): B = cache.getOrElseUpdate(a, f(a))
  }
}

import Memoization._

// Abstracting flyweight pattern 
// (http://en.wikipedia.org/wiki/Flyweight_pattern)
trait Flyweight[Args, Obj] { self: (Args => Obj) =>
  val on: Args => Obj = memoize(this : (Args => Obj))
}

// Ctrl+D

使用法:

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class IntegerWrapper private(i: Int) {
  println(this.toString + " created.")
}

object IntegerWrapper extends (Int => IntegerWrapper) 
  with Flyweight[Int, IntegerWrapper]

// Ctrl+D

scala> IntegerWrapper.on(11)
IntegerWrapper(11) created.
res0: IntegerWrapper = IntegerWrapper(11)

scala> IntegerWrapper.on(11)
res1: IntegerWrapper = IntegerWrapper(11)

これは一般的な解決策であり、Map. Vector特定のケースではを使用したほうがよい場合があります。

于 2012-11-05T13:14:51.593 に答える
3

Symbolこれは基本的に scala のクラスと同じユースケースです。そのため、Symbol.scala を合理的な実装 (特に、IntegerWrapper インスタンスが不要な場合でもメモリ内に永久に保持しない実装) のインスピレーションとして見ることができます。

https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/Symbol.scala#L1を参照してください。

于 2012-11-05T13:01:53.253 に答える
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)
}

利点は、 がケース クラスであるため、equalshashCodeが引き続きコンパイラによって生成されることです。IntegerWrapperImpl欠点は、コンパイラによって追加された他のケース クラスの機能を直接使用できないことですcopy。それを使用したい場合はIntegerWrapperImpl、クライアントに公開するか、IMHOの方が良いですが、インターフェースに追加copyしてください。IntegerWrapper

パターン マッチングは通常どおり機能します。

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
于 2012-11-05T12:58:02.333 に答える