【问题标题】:Compare instances of Option[T] avoiding None == None比较 Option[T] 的实例避免 None == None
【发布时间】:2013-01-28 18:58:22
【问题描述】:

昨天我突然豁然开朗,明白了人们如何以及为什么使用带有 Option 的“map”方法来比较值。是的,我有点慢,抱歉:)

我修改了这些非常好的链接,并提出了我想问的问题。

http://twitter.github.com/effectivescala

http://blog.tmorris.net/posts/scalaoption-cheat-sheet

在我的 Lift webapp 中,我有一些 Option[User] 和 Option[Server] 变量。我正在尝试通过以下检查来确定此用户是否是此服务器的管理员

if(user.map(_.id) == server.map(_.adminId))

但我注意到,如果 'user' 为 None 并且 'server' 也为 None,则此检查成功,这对我不利(如果其中任何一个为 None,我希望此检查失败)。我可以添加 user.isDefined 条件,但我觉得有更正确的方法可以做到这一点。你能告诉我如何用 Scala 的方式来完成它吗?

【问题讨论】:

    标签: scala


    【解决方案1】:

    您可以通过模式匹配来做到这一点(在这种情况下,这可能是最清晰的方式):

    (user, server) match {
      case (Some(user), Some(server)) if user.id == server.adminId =>
        // both ids are matching, handle this case here
      case _ =>
        // no match, handle this case here
    }
    

    您也可以尝试单线,但在这里我不建议这样做,因为它非常模糊:

    if ( user.flatMap{ user => server.map(_.adminId == user.id) }.getOrElse( false ) ) {
      // both ids are matching, handle this case here
    }
    else {
      // no match, handle this case here
    }
    

    最后,如果您只需要处理 id 匹配的情况(如果不匹配则什么都不做),使用 for 理解并不是一个太糟糕的选择(不是双关语):

    for ( user <- user; server <- server if user.id == server.adminId ) {
      // both ids are matching, handle this case here
    }
    

    【讨论】:

    • 单行可以简化一点:user.exists(u =&gt; server.exists(_.adminId==u.id))
    • 正确,很好发现。我仍然认为单行不是一个好主意,即使您的版本更加简洁(因为意图仍然有些模糊)。
    【解决方案2】:

    为此我习惯了exists / contains 的组合。

    比较同一类型的两个选项时:

    o1.exists(o2.contains)
    

    在您的情况下,可以使用map

    user.map(_.id).exists(server.map(_.adminId).contains)
    

    【讨论】:

      【解决方案3】:

      你可以使用 for 理解

      def isAdmin(server: Option[Server])(user: Option[User]): Boolean = (for {
          s <- server
          u <- user
        } yield (u.id == s.adminId)
      ).getOrElse(false)
      

      理解结果为Option[Boolean],您可以从中获得get 的值或false(如果没有值)(任何选项为None 的情况,根据您的要求)

      为什么要咖喱?

      我将方法设置为 curried,因此您可以为特定服务器定义函数,然后重用该函数来检查多个用户

      def isMyServerAdmin = isAdmin(Some(myServer)) _
      
      isMyServerAdmin(Some(user1)) = true
      isMyServerAdmin(Some(user2)) = false
      isMyServerAdmin(None) = false
      

      【讨论】:

        【解决方案4】:

        我们可以利用Option#zip 来处理元组用户/服务器的Option

        user zip server exists { case (user, server) => user.id == server.adminId }
        

        Option#zip 的行为在哪里:

        Some(User(id = "hello")) zip Some(Server(adminId = "world"))
        // Some((User("hello"), Server("world")))
        Some(User(id = "hello")) zip None        // None
        None zip Some(Server(adminId = "world")) // None
        None zip None                            // None
        

        其中Option#existszip 生成的可选元组应用谓词。

        【讨论】:

          猜你喜欢
          • 2021-03-05
          • 2022-08-18
          • 1970-01-01
          • 1970-01-01
          • 2012-10-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多