【问题标题】:Idiomatic syntax for Option when the meaningful value is None当有意义的值为 None 时,Option 的惯用语法
【发布时间】:2013-08-02 12:14:43
【问题描述】:

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

我正在调用的函数返回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!")

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

【问题讨论】:

  • 绝对是getOrElse。实际上,您也可以对生成的用户做一些事情。
  • 我会使用getOrElse。如果由于某种原因必须使用条件,请使用 .isEmpty 而不是 == None
  • 我通常把这些问题带到codereview.stackexchange.com
  • @JasonG 没有意识到这存在。你是对的,当然,我会从现在开始这样做。感谢您指出!
  • 没有人提到 getUser(name) orElse createUser(name) 创建返回选项;不过当然大家心里想的是:getUser(name).fold(createUser(name))(identity).

标签: scala coding-style


【解决方案1】:

由于您的目标是引起副作用,因此我会使用条件来强调这一点,而不是使用getOrElse

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

【讨论】:

    【解决方案2】:

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

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

    无论是模式匹配还是 getOrElse 都是合理的解决方案。通常 if 语句不用于像选项这样的 Monad - 至少不是我看到的那样。

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

    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)))
    }
    

    【讨论】:

    • 赞成,因为这是一个很好的答案 - 只是不是正确的问题。在这种特殊情况下,我不需要也不想要返回值,其目的只是确保在启动时管理员帐户存在,如果不存在则创建一个默认帐户。
    【解决方案3】:

    真正做到这一点的最好方法是将结果分配给一个有意义的变量名,这样您以后的代码就不需要知道是否调用了createUser

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

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

    【讨论】:

    • 我没有在我的问题中说明这一点,但在这种特定情况下,我不太关心结果值 - 我只想创建不存在的用户,但之后我就没有其他事情要做了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 2015-05-24
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 2011-11-05
    • 2023-02-23
    相关资源
    最近更新 更多