当有意义值为None时,Option的惯用语法

时间:2013-08-02 12:14:44

标签: scala coding-style

这纯粹是一种编码风格的问题。

我正在调用的函数返回Option,如果它等于None,我想采取特定的操作。

例如,假设我正在尝试在启动时创建默认用户(如果它尚不存在)。我会调用一个函数来尝试查找与默认用户匹配的用户,并返回Option[User]

如果返回值为None,我想运行一些用户创建代码。如果没有,我就完成了。

我想知道什么是最惯用的Scala语法。到目前为止我所拥有的是:

def getUser(name: String): Option[User] = ...

getUser("admin") getOrElse createUser("admin", "ChangeThisNow!")

getUser("admin") match {
    case None => createUser("admin", "ChangeThisNow!")
    case _    =>
}

if(getUser("admin") == None) createUser("admin", "ChangeThisNow!")

第一个解决方案似乎是最具功能性的解决方案,但我不禁觉得可能有更好的解决方案 - 可能是通过使用部分应用的函数,我承认我仍然有点模糊。

3 个答案:

答案 0 :(得分:4)

因为在你的情况下,目标是产生副作用,我会使用条件来强调,而不是使用getOrElse

if (getUser("admin").isEmpty) 
  createUser("admin", "ChangeThisNow!")

答案 1 :(得分:1)

请记住,scala是一种多范式语言。 除了语法之外,您还需要考虑内聚(单一责任)等概念,因此除了在语法中使用的实际习语外,您还可以考虑对象的组成。

OO方式可能是装饰getUser所属的对象/类,以便在包装器中创建用户,以便调用getUser函数的其他代码永远不必处理该问题。这非常适合开放/封闭原则和单一责任。这是一个贫乏的领域模型反模式,但可能会显示如何使用OO将对话扩展到实际设计中。

模式匹配或getOrElse都是合理的解决方案。通常,如果语句不用于Monads,就像选项一样 - 至少不是我看到的。

无论哪种方式,即使有副作用(用户创建),我也相信表达式应返回结果。

case class User(name: String)    

class UserService {
  def getUser(name: String): Option[User] = ???
  def createUser(name: String): User = ???
}

class UserServiceDecorator extends UserService {
  override def getUser(name: String): Option[User] =  
    Some(super.getUser(name).getOrElse(super.createUser(name)))
}

答案 2 :(得分:0)

实际上,最好的方法是将结果分配给有意义的变量名称,以便将来的代码不需要知道是否调用createUser

val user = getUser("admin").getOrElse(createUser("admin", "ChangeThisNow!"))

这样,无论您是否创建了新用户,都可以使用user变量。