Câu hỏi Là nó có thể và làm thế nào để có var mà chỉ có thể được thiết lập một lần?


Có cách nào để đảm bảo rằng một biến chỉ có thể được đặt một lần?

Hiện tại, tôi đang sử dụng phương pháp này

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]
}

8
2017-12-21 04:04


gốc


Bạn có thể sử dụng một lazy val? Khi nào biến của bạn được đặt và sử dụng? - The Archetypal Paul
Không, tôi cần userIP được đặt ở bất kỳ điểm nào - Andrey


Các câu trả lời:


Không có ngôn ngữ như vậy xây dựng, nhưng tôi nghĩ rằng tôi có thể làm sạch mã của bạn, ít nhất.

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

Sử dụng:

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

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

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

Tôi bỏ qua null xem xét vì mã Scala thành ngữ có xu hướng không sử dụng hoặc xem xét null bên ngoài khả năng tương thích Java. Chúng tôi chủ yếu giả vờ rằng nó không tồn tại.


4
2017-12-21 04:29





Bạn có thể tạo một biến cố định bằng cách sử dụng một val. Ví dụ:

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

Xem câu trả lời này để biết thêm chi tiết: https://stackoverflow.com/a/1792207/4380308

Chỉnh sửa:

Một val có thể được khai báo và sau đó khởi tạo sau này.

val a;
a = 0;

1
2017-12-21 04:09



Tôi nghĩ những gì Andrey muốn là thứ gì đó có thể có giá trị của nó được đặt sau đó. - Chris Martin
@ChrisMartin Tôi sẽ chỉnh sửa câu trả lời của tôi, tuy nhiên một val vẫn có thể được khai báo và sau đó khởi tạo sau này. - John Cipponeri
Ý tôi là... một lát sau. Giống như, không phải trong khối đó. - Chris Martin
Điều đó vẫn có thể đạt được với phạm vi của biến. - John Cipponeri
Từ một tệp hoàn toàn khác. ví dụ. clientInfo.userIP.set(...) - Chris Martin


Phương pháp tiếp cận sử dụng lười biếng:

  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

Để làm cho nó an toàn, bạn có thể sử dụng:

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

1
2017-12-21 10:30





Bạn có thể thử như sau:

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
}

Bạn có thể sử dụng điều này hơn nữa như:

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

0
2017-12-21 04:14





bạn có thể sử dụng getter đơn giản và 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

Tôi thích sử dụng Option là giá trị trực tiếp để ngăn null và NPE. Tất nhiên bạn có thể thêm những gì bao giờ logic bạn cần trong setter.


0
2017-12-21 22:14