Dan*_*Dan 2 null scala initialization
我知道解决相关问题有多个问题,但我不确定它是否确实会攻击我正在寻找的内容.经过几年的Java开发,我仍然是Scala的新手.我正在寻找测试对象是否已初始化的最佳方法,如果没有,则初始化它.例如,在Java中:
private MyObject myObj = null;
Run Code Online (Sandbox Code Playgroud)
在未来的某个时刻:
public void initMyObj(){
if (myObj == null){
myObj = new MyObj();
}
// do something with myObj
}
Run Code Online (Sandbox Code Playgroud)
在此之后,我可能会将myObj重新分配给另一个对象,但这不太可能.在Scala中,我有这个:
class Test {
var myObj: MyObj = _
}
Run Code Online (Sandbox Code Playgroud)
我已经读过我可以使用Option,比如:
var myObj = None : Option[MyObj]
Run Code Online (Sandbox Code Playgroud)
然后我的支票:
myObj match {
case None => ...
case Some(value) => ...
}
Run Code Online (Sandbox Code Playgroud)
但是当我在任何其他时间在其他任何地方都不能进行这种检查时,使用这种模式会感到很尴尬 - 尽管Scala是新手,但我可能错了.这是实现我想要的最佳方式还是没有其他选项不涉及选项?
也许你需要一个惰性变量.
lazy val myObj: MyObj = //here you put the object creation code
Run Code Online (Sandbox Code Playgroud)
通过这种方式,对象创建被推迟到代码第一次尝试访问它.
在 Scala 中留下部分构造的对象通常不是理想的做法。您通常会重新考虑如何实例化您的对象,以查看您是否不能使用不那么脆弱的其他模式。例如,不是在方法中设置未初始化的变量:
class Foo { var a: String = null; var b: String = null }
def initFooA(s: String, f: Foo) { if (f.a == null) f.a = s }
def initFooB(s: String, f: Foo) { if (f.b == null) f.b = s }
f
initFooA("salmon", f)
// Do stuff
initFooB("herring", f)
Run Code Online (Sandbox Code Playgroud)
您将尝试重构代码以按需生成所需的值,并在此之前延迟 foo 的实例化:
case class Bar(a: String, b: String) {}
def initBarA(s: String) = s
def initBarB(s: String) = s
val iba = initBarA("halibut")
// Do stuff
val ibb = initBarB("cod")
Bar(iba, ibb)
Run Code Online (Sandbox Code Playgroud)
因为 Scala 可以轻松访问元组(和类型推断),所以这比 Java 中的痛苦要少得多。
您可以做的另一件事是将后期初始化推迟给其他人。
case class Baz(a: String)(bMaker: => String) {
lazy val b = bMaker
}
Run Code Online (Sandbox Code Playgroud)
现在,您传入一些将生成参数 b 的内容,并安排它处理任何需要处理的后期初始化内容。这并不总是避免需要设置变量,但它可以帮助将它从类代码中推送到初始化逻辑中(这通常是一个更好的地方)。
使用 vars 执行此操作有点不那么简单。实际上,您可能最好只为它投入一门课,例如:
class LazyVar[A](initial: => A) {
private[this] var loaded = false
private[this] var variable: A = _
def apply() = { if (!loaded) { loaded = true; variable = initial }; variable }
def update(a: A) { loaded = true; variable = a }
}
Run Code Online (Sandbox Code Playgroud)
然后(遗憾的是)您必须()在每次读取和写入时使用。
scala> val lv = new LazyVar({ println("Hi!"); 5 })
lv: LazyVar[Int] = LazyVar@2626ea08
scala> lv()
Hi!
res2: Int = 5
scala> lv() = 7
scala> lv()
res4: Int = 7
Run Code Online (Sandbox Code Playgroud)
然后你使用这个类的一个实例而不是实际的var并通过惰性初始化器。(lazy val在幕后非常像这样;编译器只是保护您免于注意到。)
最后,如果您想拥有一个偶尔丢失值的全功能对象,var x: Option[X]那么您想要使用的构造是什么?如果您无法找到绕过标准 Java 创建模式的方法(并且您不想尝试更奇特的东西,例如使用越来越多的信息相互创建的对象,要么因为性能至关重要,而您负担不起,或者您不喜欢编写那么多样板以允许类型检查以验证您的对象是否正确创建)但您想要使用它,这var x: X = null是我选择的,而不是_. 如果X是原始值,则无论如何您可能都需要明智地选择正确的值(例如,Double.NaN代替0.0,-1而不是0forInt) 表示我未初始化。如果它是通用代码,而您想要Any而不是AnyRef, asInstanceOf-ing 在Anyand之间来回切换AnyRef可能是摆脱类型检查不佳情况的最佳方法(假设您真的,真的不能使用Option,这在这一点上要清楚得多)。