这纯粹是一种编码风格的问题。
我正在调用的函数返回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!")
第一个解决方案似乎是最具功能性的解决方案,但我不禁觉得可能有更好的解决方案 - 可能是通过使用部分应用的函数,我承认我仍然有点模糊。
答案 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
变量。