[我创建了一个虚构的 JavaClass 只是为了能够测试代码,请参阅问题末尾。]
我使用 Java 库中的增量/可变算法(Weka,但该问题适用于任何 Java 库)。我试图包装它的可变性质。一种方法是像下面的代码一样:
class Model {
private val model = new JavaModel //just a fake example (could be NaiveBayes)
//just returns the JavaModel to simplify the question.
lazy val last_state(items: Seq[Item]) = {
items foreach model.update
model
}
}
问题是有时候,一些中间状态也是需要的。 做到这一点的直接方法是为每个人保留一份副本:
class Model {
private val model = new JavaModel //just a fake example (could be NaiveBayes)
def states(items: Seq[Item]): Stream[JavaModel] =
if (items.isEmpty) Stream.Empty
else {
val h = items.head
val t = items.tail
val clone = clone(model) // (AbstractClassifier.makeCopy for weka users)
clone.update(h)
clone #:: states(t)
}
}
}
当需要获取最后一个结果时,由于所有不需要的复制,这比第一个代码慢得多。我可以将 lazy val
放入流中。但在对其求值时,实例 model
不再保证相同。
class Lazy (model: JavaModel) {
lazy val copy = clone(model) // (AbstractClassifier.makeCopy for weka users)
}
class Model {
private val model = new JavaModel //just a fake example (could be NaiveBayes)
def states(items: Seq[Item]): Stream[Lazy] =
if (items.isEmpty) Stream.Empty
else {
val h = items.head
val t = items.tail
model.update(h)
Lazy(model) #:: states(t)
}
}
}
这个丑陋的解决方案是我找到的最好的解决方案。我有非私有(private)可变字段等:
class JavaClass(initial:Int = 1) {
//represents a lot of data structures
private var state = initial
//Int represents something more complex
def update(h: Int) {
println("Some heavy calculations performed. State=" + state)
state += 1
}
def copy = new JavaClass(state)
//other methods that make use of the state ...
}
case class Lazy(java_object: JavaClass) {
var lazy_var: Option[JavaClass] = null
def copied = if (lazy_var == null) {
lazy_var = Some(java_object.copy)
lazy_var
} else lazy_var
}
class Model {
def states(items: Seq[Int]): Stream[Lazy] = {
val java_class = new JavaClass
def rec(items: Seq[Int], laz: Lazy): Stream[Lazy] =
if (laz != null && items.isEmpty) Stream.Empty
else {
if (laz.lazy_var == null) laz.lazy_var = None
val h = items.head
val t = items.tail
java_class.update(h)
val new_laz = Lazy(java_class)
new_laz #:: rec(t, new_laz)
}
rec(items, Lazy(null))
}
}
//Test:
scala> val m = new Model
m: Model = Model@726b80fa
scala> val states = m.states(Seq(1, 2, 3, 4, 5))
Some heavy calculations performed. State=1
states: Stream[Lazy] = Stream(Lazy(JavaClass@283e1abf), ?)
scala> states(0).copied match {case Some(x) => x; case None => -1}
res31: Any = JavaClass@1029bf49
scala> states(3).copied match {case Some(x) => x; case None => -1}
Some heavy calculations performed. State=2
Some heavy calculations performed. State=3
Some heavy calculations performed. State=4
res32: Any = JavaClass@3cb40c69
scala> states(3).copied match {case Some(x) => x; case None => -1}
res33: Any = JavaClass@3cb40c69
scala> states(1).copied match {case Some(x) => x; case None => -1}
res34: Any = -1
最佳答案
一个好的地方是使用“_= posfix”从“人工字段”开始,如本site 的示例中所述。 .也许最好用正确的驼峰命名法打开一个新问题。
// Fields may be artificial:
class H {
private var realX = 0
def x = realX
// called for "this.x = <value>":
def x_=(newX : Int) {
this.realX = newX
}
}
关于java - 如何在不急于浪费内存的情况下将增量可变 Java 类包装在函数式 Scala 类中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21972165/