Scala:在不使用val的情况下分配变量一次
这就是我想做的-Scala:在不使用val的情况下分配变量一次,scala,Scala,这就是我想做的- class A(some args) { var v: SomeType = null def method1(args) = { v = something1 ... method3 } def method2(args) = { v = something2 ... method3 } def method3 = { // uses v } } 在这种特定情况下,method1和Meth
class A(some args) {
var v: SomeType = null
def method1(args) = {
v = something1
...
method3
}
def method2(args) = {
v = something2
...
method3
}
def method3 = {
// uses v
}
}
在这种特定情况下,method1和Method2是互斥的,在A实例的生命周期中,它们中的任何一个都只被调用一次。此外,v被赋值一次。我更喜欢将其设置为val,但因为我需要method2或method3的上下文来初始化v,所以我不能在构造函数中这样做
如何实现这种“val”行为?我可以考虑修改方法1和方法2来应用方法,但我不喜欢这个想法。此外,method1和Method2具有相同的参数签名(因此apply需要更多的信息来区分这两种类型的调用)。一个重要的问题是:您究竟将“val行为”称为什么?对我来说,“val行为”是在声明时立即赋值一次的行为,可以静态地强制执行。您似乎想要强制执行
v
未分配两次。您可能还希望强制在分配之前从不读取它。您可以为此创建一个非常小的辅助框:
final class OnceBox[A] {
private[this] var value: Option[A] = None
def update(v: A): Unit = {
if (value.isDefined)
throw new IllegalStateException("Value assigned twice")
value = Some(v)
}
def apply(): A = {
value.getOrElse {
throw new IllegalStateException("Value not yet assigned")
}
}
}
现在是您的代码片段:
class A(some args) {
val v = new OnceBox[SomeType]
def method1(args) = {
v() = something1
...
method3
}
def method2(args) = {
v() = something2
...
method3
}
def method3 = {
// uses v
v()
}
}
哦,开玩笑吧,但是内置了单任务VAL:-p类似的东西可能:
class A private (mtdType: Int, ...) {
val v = mdtType match {
case 1 => method1(...)
case 2 => method2(...)
}
}
object A {
def withMethod1(...) = new A(1, ...)
def withMethod2(...) = new A(2, ...)
}
或者,另一种可能性:
sealed trait A {
val v
def method3 = println(v)
}
class Method1(...) extends A {
val v = method1(...)
}
class Method2(...) extends A {
val v = method2(...)
}
与另一个答案类似,但不是子类型,而是字段
scala> :pa
// Entering paste mode (ctrl-D to finish)
class A {
private[this] var context: Int = _
lazy val v: String =
context match {
case 1 => "one"
case 2 => "two"
case _ => ???
}
def m1() = { context = 1 ; v }
def m2() = { context = 2 ; v }
}
// Exiting paste mode, now interpreting.
defined class A
scala> val a = new A
a: A = A@62ce72ff
scala> a.m2
res0: String = two
scala> a.m1
res1: String = two
为什么不能将
v
值作为参数传递给m3
?m3
是否从类的外部调用?如果是,可以在m1
或m2
之前调用m3
?(听起来像是一个设计缺陷。)我觉得你只需要强制执行method1
或method2
只能调用一次,而method3
只能在以后调用。@jwvh m3是一个私有方法,我应该在我的代码片段中提到这一点。@Jasper-M我目前正通过保留一个var并检查null和抛出异常(如果不是)来确保这种排序,这是sjrd的解决方案。我一直在寻找一个更简单/更干净的解决方案。v
抛出直到设置好上下文,然后正常工作。我之前考虑过这个想法。但我的特定用例的问题是,它是一个复杂的初始化(许多变量以m1和m2计算)。因此,上下文必须是一组值(可能是一个包含所需字段的类)。当然,我可以扩展这种方法,并说-v和context是同一类型的,并且在将结果分配给同一对象时也是如此。但这太复杂了,无法在未来的开发人员身上实施,他们使用v而不是上下文。