Scala:仅在对象尚不存在的情况下创建对象

时间:2016-07-25 14:50:54

标签: scala object

我是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

那么,我该怎么做?任何和所有的帮助将非常感激。

2 个答案:

答案 0 :(得分:2)

我认为您的GetFromDatabase会返回nullPushMessage,因此要正确模式匹配,您需要将其包装到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进一步传递它,我会完全接受它。