是否可以仅使用val:
在Scala中执行此操作class MyClass {
private val myVal1: MyClass2 //.....????? what should be here?
def myMethod1(param1: Int) = {
myVal1 = new MyClass2(param1)
//....
// some code....
}
}
我的想法是我无法立即初始化myVal1
,因为其构造函数的参数尚未知,我必须在myMethod1
中执行此操作。 <{1}}应该在类中可见,并且应该是不可变的。
不允许任何可变状态。
有可能吗?
答案 0 :(得分:4)
不,不可能按照你想要的方式去做。考虑一下,
的结果是什么val mc = new MyClass
mc.method1(0)
mc.method1(1)
?设置myVal1
两次抛出异常?还是应该保留第一个值?
答案 1 :(得分:3)
这是不可能的,但有一些方法(除了使用param1作为构造函数参数)
var
更改为Option
; setter myMethod1
返回同一个类的新实例,并将Option
设置为该值。Builder
创建一个单独的可变var
类,并在收集完所有数据后将其转换为不可变的类lazy val
s(example 1,example 2)更新:1:
的示例class MyClass(val myVal1: Option[Int]) {
def myMethod1(param1: Int): MyClass = {
new MyClass(Some(param1))
}
}
object MyClass {
def apply() = new MyClass(None)
def apply(i: Int) = new MyClass(Some(i))
}
例如,immutable.Queue使用此模式。
更新:3(循环参考)的示例:
// ref ... call by name
class MyClass(val id: Int, ref: => MyClass) {
lazy val myVal1 = ref
override def toString: String = s"$id -> ${myVal1.id}"
}
这样使用:
val a: MyClass = new MyClass(1, b)
val b: MyClass = new MyClass(2, a)
println(a)
println(b)
更新:3(前向参考)的示例:
class MyClass2(val id: Int)
// ref ... call by name
class MyClass(val id: Int, ref: => MyClass2) {
lazy val myVal1 = ref
override def toString: String = s"$id -> ${myVal1.id}"
}
与
一起使用val a = new MyClass(1, x)
println(a.id) // You can use a.id, but not yet the lazy val
val x = new MyClass2(10)
println(a)
答案 2 :(得分:0)
模仿懒惰的价值&#34;在实例初始化完成之后,可能无法检索其初始值(顺便说一下,这些对象没有什么特别之处,例如Swift有lazy properties,甚至建议将其声明为变量),你可以引入一个包装来重复Scala编译器在内部为Scala中的延迟值生成的相同逻辑:
class LazyVar[T] {
private[this] var value$compute: () => T = () => null.asInstanceOf[T]
@volatile private[this] var value$: T = null.asInstanceOf[T]
@volatile private[this] var isInitialized$ = false
@volatile private[this] var isComputed$ = false
def value_=(value: T) = this.synchronized {
if(!isInitialized$) {
value$compute = () => value
isInitialized$ = true
}
else throw new IllegalStateException("Already initialized")
}
def value: T = this.synchronized {
if(!isInitialized$) throw new IllegalStateException("Not yet initialized")
else if(isComputed$) value$
else {
value$ = value$compute()
isComputed$ = true
value$
}
}
}
现在您只需将MyClass2
更改为LazyVar[MyClass2]
即可保留val
关键字:
case class MyClass2(param: Int)
class MyClass {
private val myVal1: LazyVar[MyClass2] = new LazyVar[MyClass2]
def this(param: Int) {
this()
println("Storing the result of an expensive function...")
myVal1.value = new MyClass2(param)
}
def debug() = println(myVal1.value)
}
现在,如果你写了像
这样的东西val myClass = new MyClass(42)
myClass.debug
myClass.debug
您将看到该值仅计算一次:
Storing the result of an expensive function...
MyClass2(42)
MyClass2(42)