假设明确:
case class IntegerWrapper(i : Int)
并且处于可能会创建IntegerWrapper
个i=[0..N>
个[IntegerWrapper(0) .. IntegerWrapper(N)>
个实例的情况下,需要做什么:
将此范围映射到一组固定的单例IntegerWrapper
保留类java.lang.Integer
的现有值语义(匹配,等号,哈希码,序列化)
我希望实例分享类似apply(i : Int)
所做的事情。我想我的问题是,如果可以在不必自己做所有事情的情况下完成。简单地使用{{1}}定义伴随对象不会编译。有什么建议吗?
答案 0 :(得分:6)
如果你只是想避免分配,也许你想要的是value class?在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
请注意,在那里调用的扩展方法是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
实例的方法的调用。
答案 1 :(得分: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
。
答案 2 :(得分:3)
这与scala的Symbol
类基本相同。因此,您可以将Symbol.scala视为合理实现的灵感(特别是,即使不需要,也不会将IntegerWrapper实例永久保留在内存中)。
答案 3 :(得分: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)
}
优点是编译器仍然生成equals
和hashCode
,因为IntegerWrapperImpl
是一个案例类。缺点是您不能直接使用其他编译器添加的案例类好东西,例如copy
。如果您想使用它,请将IntegerWrapperImpl
公开给客户端,或者更好地将IMHO添加到copy
界面。
模式匹配照常工作:
IntegerWrapper