在相同的情况下,Scala模式匹配None和Some()

eufgjt7s  于 2022-11-09  发布在  Scala
关注(0)|答案(2)|浏览(178)

在同一个大小写中有None和Some()的情况下最优雅的情况是什么?类似于:

val data: Option[Int] = getSomeData()

data match {
 case None || Some(data) && data > 50 =>
 case _ =>
}
jxct1oxe

jxct1oxe1#

您可以使用Option.forall作为条件。

def foo(data: Option[Int]): Unit =
  if (data.forall(_ > 50)) println("OK")
  else println("KO")

foo(None)
// => OK

foo(Some(1))
// => KO

foo(Some(51))
// OK
f4t66c6m

f4t66c6m2#

通常,这样的模式匹配可以写成如下

data match {
  case None                    => doSomething()
  case Some(data) if data > 50 => doSomething()
  case _                       => doOther()
}

如果这种组合(None || Some(data) && data > 50)经常发生,您可以引入定制的提取程序

object GreaterThan50OrEmpty {
  def unapply(arg: Option[Int]): Boolean = arg match {
    case None                    => true
    case Some(data) if data > 50 => true
    case _                       => false
  }
}

data match {
  case GreaterThan50OrEmpty() => println("matches pattern")
  case _                      => println("default")
}

你甚至可以随意叫它

object `None || Some(data) && data > 50` {
  def unapply(arg: Option[Int]): Boolean = arg match {
    case None                    => true
    case Some(data) if data > 50 => true
    case _                       => false
  }
}

data match {
  case `None || Some(data) && data > 50`() => println("matches pattern")
  case _                                   => println("default")
}

稍微笼统一点的方法

class GreaterThanOrEmpty(dataBound: Int) {
  def unapply(arg: Option[Int]): Boolean = arg match {
    case None                           => true
    case Some(data) if data > dataBound => true
    case _                              => false
  }
}

val GreaterThan50OrEmpty = new GreaterThanOrEmpty(50)

data match {
  case GreaterThan50OrEmpty() => println("matches pattern")
  case _                      => println("default")
}

您甚至可以自动生成这样的unapply(尽管我想这不值得)

import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

@compileTimeOnly("enable macro paradise")
class extractor[A] extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro ExtractorMacro.impl
}

object ExtractorMacro {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._
    val typA = c.prefix.tree match {
      case q"new extractor[$a]" => a
    }
    annottees match {
      case q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" :: Nil =>
        val cases = tname.decoded.split('|').map(s => s"case $s => true").mkString("\n")
        val casesTree = c.parse(
          s"""arg match {
             | $cases
             | case _ => false
             |}""".stripMargin)
        q"""$mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
          ..$body
          def unapply(arg: $typA): Boolean = $casesTree
        }"""
      case _ => c.abort(c.enclosingPosition, "not object")
    }
  }
}

用途:

@extractor[Option[Int]]
object `Some(x) if x < 25 | None | Some(data) if data > 50`

//Warning:scalac: object ... extends scala.AnyRef {
//  ...
//  def unapply(arg: Option[Int]): Boolean = arg match {
//    case Some((x @ _)) if x.$less(25)          => true
//    case None                                  => true
//    case Some((data @ _)) if data.$greater(50) => true
//    case _                                     => false
//  }
//}

def test(arg: Any) = arg match {
  case `Some(x) if x < 25 | None | Some(data) if data > 50`() => 
    println("matches pattern")
  case _ => println("default")
}

test(None)     // matches pattern
test(Some(51)) // matches pattern
test(Some(24)) // matches pattern
test(Some(30)) // default

相关问题