Scala:在没有val的情况下分配一次变量

时间:2016-12-10 20:08:57

标签: 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
  }
}

在这种特定情况下,方法1和2是互斥的,并且在A的实例的生命周期中,其中一个被恰好调用一次。此外,v被分配一次。我宁愿把它变成val。但是因为我需要method2或method3的上下文来初始化v,所以我不能在构造函数中这样做。

如何实现这个" val"行为?我可以考虑修改method1和method2来应用方法,但我不喜欢这个想法。此外,method1和2具有相同的参数签名(因此应用需要更多信息来区分这两种类型的调用)。

3 个答案:

答案 0 :(得分:8)

一个重要的问题是:你究竟打电话给什么" 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()
  }
}

哦,开个玩笑,但是Ozma内置了单一赋值的val :-p

答案 1 :(得分:5)

与其他答案类似的想法,但不是子类型,而是一个字段。

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

答案 2 :(得分:3)

这样的事情可能是:

render() {
    const { potions, className } = this.state;

    if (!potions) {
      return (<p>Loading...</p>);
    } else {
      return (
          <div className="{className}">
              <ul>
                  {potions.map(potion => <li key={potion.id}>{potion.name}</li> )}
              </ul>
          </div>
      );
    }
}

或者,另一种可能性:

   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, ...)
   }