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")
中为空).
But it doesn't work! (properties
is null in properties.get("forum_id")
).
为什么会这样?loadedProps
被 properties
引用时不评估吗?
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屋!