Scala - vals 的初始化顺序 [英] Scala - initialization order of vals
问题描述
我有一段从文件加载属性的代码:
I have this piece of code that loads Properties from a file:
class Config {
val properties: Properties = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
val forumId = properties.get("forum_id")
}
这似乎工作正常.
我尝试将 properties
的初始化移动到另一个 val,loadedProperties
,如下所示:
I have tried moving the initialization of properties
into another val, loadedProperties
, like this:
class Config {
val properties: Properties = loadedProps
val forumId = properties.get("forum_id")
private val loadedProps = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
}
但它不起作用!(properties
在 properties.get("forum_id")
中为 null).
But it doesn't work! (properties
is null in properties.get("forum_id")
).
为什么会这样?当被 properties
引用时,不评估 loadedProps
吗?
Why would that be? Isn't loadedProps
evaluated when referenced by properties
?
其次,这是初始化需要非平凡处理的变量的好方法吗?在 Java 中,我会声明它们 final
字段,并在构造函数中执行与初始化相关的操作.
Secondly, is this a good way to initialize variables that require non-trivial processing? In Java, I would declare them final
fields, and do the initialization-related operations in the constructor.
Scala 中是否有针对此场景的模式?
Is there a pattern for this scenario in Scala?
谢谢!
推荐答案
Vals 按照它们声明的顺序初始化(嗯,准确地说,non-lazy vals 是),所以 properties
在 loadedProps
之前被初始化.或者换句话说,当 properties
被初始化时,loadedProps
仍然是 null
.这里最简单的解决方案是在 properties
之前定义 loadedProps
:
Vals are initialized in the order they are declared (well, precisely, non-lazy vals are), so properties
is getting initialized before loadedProps
. Or in other words, loadedProps
is still null
when properties
is getting initialized.
The simplest solution here is to define loadedProps
before properties
:
class Config {
private val loadedProps = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
val properties: Properties = loadedProps
val forumId = properties.get("forum_id")
}
你也可以让 loadedProps
延迟,这意味着它会在第一次访问时被初始化:
You could also make loadedProps
lazy, meaning that it will be initialized on its first access:
class Config {
val properties: Properties = loadedProps
val forumId = properties.get("forum_id")
private lazy val loadedProps = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
}
使用惰性 val 的优点是您的代码对重构更加健壮,因为仅更改 val 的声明顺序不会破坏您的代码.
Using lazy val has the advantage that your code is more robust to refactoring, as merely changing the declaration order of your vals won't break your code.
此外,在这种特殊情况下,您可以将 loadedProps
转换为 def
(如@NIA 建议的那样),因为它无论如何都只使用一次.
Also in this particular occurence, you can just turn loadedProps
into a def
(as suggested by @NIA) as it is only used once anyway.
这篇关于Scala - vals 的初始化顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!