【问题标题】:Is it possible and how to have var that can only be set once?是否有可能以及如何让 var 只能设置一次?
【发布时间】:2015-02-19 14:30:36
【问题描述】:

是否有本地方法来确保变量只能设置一次?

目前,我正在使用这种方法

class SetOnceVariable[T]
{
  private var value : T = _

  private var initialized = false

  def apply(_v : T = _) : T =
  {
    if (value != null && !initialized) {
      value = _v
      initialized = true
    }
    value
  }
}

class ClientInfo
{
  val userIP : SetOnceVariable[String] = new SetOnceVariable[String]
}

【问题讨论】:

  • 你能用lazy val吗?您的变量何时设置和使用?
  • 不,我需要在任何时候设置用户IP

标签: scala


【解决方案1】:

没有这样的语言结构,但我想我至少可以清理你的代码。

class SetOnce[A](var toOption: Option[A] = None) {
    def set(a: A): Unit = if (toOption.isEmpty) toOption = Some(a)
    def get: A = toOption.get
}

用法:

val x = new SetOnce[Int]
x.toOption // None

x.set(1)
x.get // 1

x.set(2)
x.get // 1

我省略了 null 的考虑,因为惯用的 Scala 代码倾向于在 Java 兼容性之外使用或考虑 null。我们大多假装它不存在。

【讨论】:

    【解决方案2】:

    使用惰性的方法:

      class SetOnceVariable[T] {
    
        private var v: T = _
        private lazy val value: T = v
    
        def apply(_v: T = ???): T = {
          v = _v
          value
        }
      }
    
    val info = new ClientInfo
    println(info.userIP("IP")) // IP
    println(info.userIP("IP2")) // IP
    println(info.userIP("IP3")) // IP
    

    为了使其线程安全,您可以使用:

    def apply(_v: T = ???): T =
      synchronized {
        v = _v
        value
      }
    

    【讨论】:

      【解决方案3】:

      您可以使用 val 创建一个常量变量。例如:

      val a = 0; // Cannot be changed
      var b = 0; // Can be changed
      

      更多详情请查看此答案:https://stackoverflow.com/a/1792207/4380308

      编辑:

      可以声明一个 val,然后也可以稍后对其进行初始化。

      val a;
      a = 0;
      

      【讨论】:

      • 我认为 Andrey 想要的是可以在以后设置其值的东西。
      • @ChrisMartin 我将编辑我的答案,但是仍然可以声明一个 val,然后稍后再初始化。
      • 我的意思是……稍后。就像,不在那个街区。
      • 考虑到变量的范围,这仍然可以实现。
      • 来自一个完全不同的文件。例如clientInfo.userIP.set(...)
      【解决方案4】:

      您可以尝试以下方法:

      class varSingleton[A >: Null <: AnyRef] {
        private[this] var _a = null: A
        def :=(a: A) { if (_a eq null) _a = a else throw new IllegalStateException }
        def apply() = if (_a eq null) throw new IllegalStateException else _a
      }
      

      您可以进一步使用它:

      var singleVal = new varSingleton[Integer]
      singleVal := 12
      singleVal() // returns 12
      singleVal := 13 //IllegalStateException
      

      【讨论】:

        【解决方案5】:

        你可以使用简单的getter和setter:

        class ClientInfo {
          private var _userIP: Option[String] = None
          def userIP: String = _userIP.get
          def userIP_=(value: String): Unit = {
            _userIP = _userIP.orElse(Option(value))
          }
        }
        
        val clientInfo = new ClientInfo()                       //> clientInfo : controllers.stackoverflow.ClientInfo controllers.stackoverflow$Clien
                                                                //| tInfo@4fccd51b
        clientInfo.userIP = "first"
        clientInfo.userIP                                       //> res0: String = first
        
        clientInfo.userIP = "second"
        clientInfo.userIP                                       //> res1: String = first
        

        我更喜欢直接使用 Option 表示值来防止空值和 NPE。您当然可以在 setter 中添加您需要的任何逻辑。

        【讨论】:

          猜你喜欢
          • 2016-06-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-06
          相关资源
          最近更新 更多