我是Scala的新手,这可能是一个非常简单的问题,但我还在努力弄清楚如何制作一个物品,只有当它还没有存在时。
我想查询数据库,并查看是否存在任何内容,如果存在,则将其存储在对象中,否则创建一个新对象。在Java中,我知道这就像
PushMessage push = null;
if(GetFromDatabase() == null) {
push = new PushMessaage(param1, param2...);
}
else {
push = GetFromDatabase();
}
但是,我如何在Scala中执行此操作。当我尝试做同样的事情时,它告诉我GetFromDatabase()不符合预期的类型Null。同样,我尝试进行模式匹配并执行类似
的操作val push = GetFromDatabase match {
case Some(pushMessage) => pushMessage
case None => new PushMessage(param1, param2...)
}
但是,这也没有奏效,因为它告诉我
构造函数无法实例化为期望的类型,找到:某些[A],预期:PushMessage
那么,我该怎么做?任何和所有的帮助将非常感激。
答案 0 :(得分:2)
我认为您的GetFromDatabase
会返回null
或PushMessage
,因此要正确模式匹配,您需要将其包装到Option
:
val push = Option(GetFromDatabase) match {
case Some(pushMessage) => pushMessage
case None => new PushMessage(param1, param2...)
}
或(糟糕的风格,但要理解它是如何工作的):
// Option(null) === None, Option(notNull) === Some(notNull):
// same as `if (x ne null) Some(x) else None
val pushMaybe: Option[PushMessage] = Option(GetFromDatabase)
val push: PushMessage =
if (pushMaybe.isEmpty) new PushMessage(param1, param2...)
else pushMaybe.get
您可以使用以下方式简化:
val push = Option(GetFromDatabase).getOrElse(new PushMessage(param1, param2...))
P.S。如果GetFromDatabase
不是某种外部方法,最好将其重写为返回Option[PushMessage]
而不是PushMessage
,例如:
def getFromDatabase = {
val rs = driver.getResulSet(query)
if (!rs.isBeforeFirst()) None else Some(parse(rs))
}
答案 1 :(得分:0)
这里有一个小小的演示,为什么“酷”的东西并不总是很酷。让我们看看Scala为两种情况生成代码(我让它们非常简单):
def getMessage: String = null
val m = getMessage
val push = if (m == null) new AnyRef else m
=>
iw.this.m = iw.this.getMessage();
iw.this.push = if (iw.this.m().==(null))
new Object()
else
iw.this.m();
VS
def getMessage: String = null
val push = Option(getMessage) match {
case Some(x) => x
case None => new AnyRef
}
=>
iw.this.push = {
case <synthetic> val x1: Option = scala.Option.apply(iw.this.getMessage());
case6(){
if (x1.$isInstanceOf[Some]())
{
<synthetic> val x2: Some = (x1.$asInstanceOf[Some](): Some);
{
val x: String = x2.x().$asInstanceOf[String]();
matchEnd5(x)
}
}
else
case7()
};
case7(){
if (scala.None.==(x1))
matchEnd5(new Object())
else
case8()
};
case8(){
matchEnd5(throw new MatchError(x1))
};
matchEnd5(x: Object){
x
}
};
因此,只要我们不传播null
(我们没有),我认为第二种选择没有任何优势。
<强>更新强>
根据要求:
val path = Option(m).getOrElse(new AnyRef)
=&GT;
final <artifact> private[this] def $anonfun$1(): Object = new Object();
...
iw.this.path = scala.Option.apply($line13.iw.m()).getOrElse({
(() => iw.this.$anonfun$1())
});
我不会认为它比上面的第二个选项好多了。 getOrElse
隐藏了相同的逻辑,我们有匿名函数,因为getOrElse
采用了名字参数。
事实上,这不仅仅是关于拯救周期。构建和解构Option
对象是为了避免本地null
?或者保存一行?如果我们使用Option
进一步传递它,我会完全接受它。