Scala 初始化那些在运行时字段中更改的正确方法:placeholder/null、None 或零元素?
Scala proper way to initialize ones changed in runtime fields: placeholder/null, None or zero element?
我得到 class 初始化时的值未知的字段。但是之后,在运行时将获取值并将其设置为字段 just ones。
我想决定最适合用于该字段的首次初始化。正如我所读,有这样的方法:
使用占位符 _
或 null
[错误的方式]:
var name: String = _
var nextUser: User = null
使用None
,比我的代码Some(v)
[好,但冗长]:
var name: Option[String] = None
var nextUser: Option[User] = None
使用 "zero" 元素:
var name: String = ""
var nextUser: User = new User()
使用存根:
var name: String = "undefined"
var nextUser: User = UndefinedUser
我看到 3 个问题:
- 从
Some()
获取值是冗长的,任何时候写 .get
或使用 match/case
- 将
var
用于字段是不好的,它实际上只会按值设置一次,但在运行时
- 写出类似
updateUser
的方法是不好的
现在我在那些字段中使用 None
,因为对于某些不在我的库中的类型,没有任何 constructor
或 empty
\"zero"值:
class ClassWithLazyFields {
var name: String = ""
var age: Int = 0
//here, after first asignment as `None` i will set it values only one time
var myThread: Option[Thread] = None
var nextUser: Option[User] = None
var myTransformUnit: Option[TransformUnit] = None
def updateUser(u: User): Unit = {
nextUser = u
}
}
//after first asignment as `None` i set nextUser value like that
classInstance.updateUser(userCat)
// bad ".get" in callings
val name = classInstance.myThread.get.name
val hoursToStart = classInstance.myTransformUnit.get.waitTime.hours
// or more verbose match/case
val hoursToStart = classInstance.myTransformUnit match {
case Some(v) => v.waitTime.hours
case None => 0
}
有什么可以指教的吗?
我需要类似 lazy var
的东西或任何好的建议。
建议首先避免使用像这样的可变数据结构。
使 class 不可变并将 updateUser
等方法更改为 return 新的更新实例,而不是修改当前实例。
但是如果您必须这样做,Option
是专门为值可能存在或不存在的情况而设计的。 map
和 getOrElse
等方法可以轻松(安全)地使用 Option
值,而且开销很小。
例如,这是您安全计算 name
和 hoursToStart
:
的方式
val name = classInstance.myThread.fold("NoName")(_.name)
val hoursToStart = classInstance.myTransformUnit.fold(0)(_.waitTime.hours)
如果您想使用多个 Option
值,请像这样使用 for
:
for {
thread <- classInstance.myThread
user <- classInstance.nextUser
unit <- classInstance.myTransformUnit
} {
// Code that uses thread, user, and unit
}
仅当所有三个值都不是 None
时才会调用代码。
我得到 class 初始化时的值未知的字段。但是之后,在运行时将获取值并将其设置为字段 just ones。
我想决定最适合用于该字段的首次初始化。正如我所读,有这样的方法:
使用占位符
_
或null
[错误的方式]:var name: String = _ var nextUser: User = null
使用
None
,比我的代码Some(v)
[好,但冗长]:var name: Option[String] = None var nextUser: Option[User] = None
使用 "zero" 元素:
var name: String = "" var nextUser: User = new User()
使用存根:
var name: String = "undefined" var nextUser: User = UndefinedUser
我看到 3 个问题:
- 从
Some()
获取值是冗长的,任何时候写.get
或使用match/case
- 将
var
用于字段是不好的,它实际上只会按值设置一次,但在运行时 - 写出类似
updateUser
的方法是不好的
现在我在那些字段中使用 None
,因为对于某些不在我的库中的类型,没有任何 constructor
或 empty
\"zero"值:
class ClassWithLazyFields {
var name: String = ""
var age: Int = 0
//here, after first asignment as `None` i will set it values only one time
var myThread: Option[Thread] = None
var nextUser: Option[User] = None
var myTransformUnit: Option[TransformUnit] = None
def updateUser(u: User): Unit = {
nextUser = u
}
}
//after first asignment as `None` i set nextUser value like that
classInstance.updateUser(userCat)
// bad ".get" in callings
val name = classInstance.myThread.get.name
val hoursToStart = classInstance.myTransformUnit.get.waitTime.hours
// or more verbose match/case
val hoursToStart = classInstance.myTransformUnit match {
case Some(v) => v.waitTime.hours
case None => 0
}
有什么可以指教的吗?
我需要类似 lazy var
的东西或任何好的建议。
建议首先避免使用像这样的可变数据结构。
使 class 不可变并将 updateUser
等方法更改为 return 新的更新实例,而不是修改当前实例。
但是如果您必须这样做,Option
是专门为值可能存在或不存在的情况而设计的。 map
和 getOrElse
等方法可以轻松(安全)地使用 Option
值,而且开销很小。
例如,这是您安全计算 name
和 hoursToStart
:
val name = classInstance.myThread.fold("NoName")(_.name)
val hoursToStart = classInstance.myTransformUnit.fold(0)(_.waitTime.hours)
如果您想使用多个 Option
值,请像这样使用 for
:
for {
thread <- classInstance.myThread
user <- classInstance.nextUser
unit <- classInstance.myTransformUnit
} {
// Code that uses thread, user, and unit
}
仅当所有三个值都不是 None
时才会调用代码。