处理 Scala 选项[T]

发布于 2024-12-21 17:53:05 字数 426 浏览 4 评论 0原文

我有一个 Scala Option[T]。如果值为 Some(x) 我想使用不返回值 (Unit) 的进程来处理它,但如果它为 None,我想打印一个错误。

我可以使用以下代码来执行此操作,但我知道更惯用的方法是将 Option[T] 视为序列并使用 map, foreach 等。我该怎么做?

opt match {
  case Some(x) => // process x with no return value, e.g. write x to a file
  case None => // print error message
}

I have a Scala Option[T]. If the value is Some(x) I want to process it with a a process that does not return a value (Unit), but if it is None, I want to print an error.

I can use the following code to do this, but I understand that the more idiomatic way is to treat the Option[T] as a sequence and use map, foreach, etc. How do I do this?

opt match {
  case Some(x) => // process x with no return value, e.g. write x to a file
  case None => // print error message
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北凤男飞 2024-12-28 17:53:05

我认为显式模式匹配最适合您的用例。

I think explicit pattern matching suits your use case best.

朱染 2024-12-28 17:53:05

遗憾的是,Scala 的 Option 缺少执行此操作的方法。我添加一个:

class OptionWrapper[A](o: Option[A]) {
  def fold[Z](default: => Z)(action: A => Z) = o.map(action).getOrElse(default)
}
implicit def option_has_utility[A](o: Option[A]) = new OptionWrapper(o)

它的用法稍微好一点(在我看来)。

op.fold{ println("Empty!") }{ x => doStuffWith(x) }

从它的定义方式可以看出,可以使用 map/getOrElse 来代替模式匹配。

或者,Either 已经有一个 fold 方法。所以你可以,

op.toRight(()).fold{ _ => println("Empty!") }{ x => doStuffWith(x) }

但这有点笨拙,因为你必须提供左值(这里 (),即单位),然后在其上定义一个函数,而不是仅仅说明你想要发生的事情在上。

模式匹配也不错,特别是对于较长的代码块。对于短距离比赛来说,比赛的开销开始阻碍得分。例如:

op.fold{ printError }{ saveUserInput }

语法开销比

op match {
  case Some(x) => saveUserInput(x)
  case None => printError
}

and 因此,一旦你期望它,就更容易理解。

Scala's Option is, sadly, missing a method to do exactly this. I add one:

class OptionWrapper[A](o: Option[A]) {
  def fold[Z](default: => Z)(action: A => Z) = o.map(action).getOrElse(default)
}
implicit def option_has_utility[A](o: Option[A]) = new OptionWrapper(o)

which has the slightly nicer (in my view) usage

op.fold{ println("Empty!") }{ x => doStuffWith(x) }

You can see from how it's defined that map/getOrElse can be used instead of pattern matching.

Alternatively, Either already has a fold method. So you can

op.toRight(()).fold{ _ => println("Empty!") }{ x => doStuffWith(x) }

but this is a little clumsy given that you have to provide the left value (here (), i.e. Unit) and then define a function on that, rather than just stating what you want to happen on None.

The pattern match isn't bad either, especially for longer blocks of code. For short ones, the overhead of the match starts getting in the way of the point. For example:

op.fold{ printError }{ saveUserInput }

has a lot less syntactic overhead than

op match {
  case Some(x) => saveUserInput(x)
  case None => printError
}

and therefore, once you expect it, is a lot easier to comprehend.

瑾兮 2024-12-28 17:53:05

我建议简单而安全地使用 opt.get ,如果 optNone ,它本身会抛出 NoSuchElementException 异常。或者如果你想抛出自己的异常,你可以这样做:

val x = opt.getOrElse(throw new Exception("Your error message"))
// x is of type T

I'd recommend to simply and safely use opt.get which itself throws a NoSuchElementException exception if opt is None. Or if you want to throw your own exception, you can do this:

val x = opt.getOrElse(throw new Exception("Your error message"))
// x is of type T
坏尐絯 2024-12-28 17:53:05

正如@missingfaktor所说,您正处于模式匹配给出最可读结果的确切场景中。
如果 Option 有一个值,你想做某事,如果没有,你想做别的事。

虽然有多种方法可以在选项类型上使用映射和其他函数构造,但它们通常在以下情况下很有用:

您想要使用 Some 情况并忽略 None 情况,例如在您的情况下

opt.map(writeToFile(_)) //(...if None just do nothing)

,或者您想要对多个选项进行链接操作并且只有当它们全部都是 Some 时才给出结果。例如,这样做的一种方法是:

val concatThreeOptions = 
for {
  n1 <- opt1
  n2 <- opt2
  n3 <- opt3
} yield n1 + n2 + n3 // this will be None if any of the three is None
                     // we will either write them all to a file or none of them

但这些似乎都不是你的情况

as @missingfaktor says, you are in the exact scenario where pattern matching is giving the most readable results.
If Option has a value you want to do something, if not you want to do something else.

While there are various ways to use map and other functional constructs on Option types, they are generally useful when:

you want to use the Some case and ignore the None case e.g. in your case

opt.map(writeToFile(_)) //(...if None just do nothing)

or you want to chain the operations on more than one option and give a result only when all of them are Some. For instance, one way of doing this is:

val concatThreeOptions = 
for {
  n1 <- opt1
  n2 <- opt2
  n3 <- opt3
} yield n1 + n2 + n3 // this will be None if any of the three is None
                     // we will either write them all to a file or none of them

but none of these seem to be your case

栀梦 2024-12-28 17:53:05

模式匹配是这里的最佳选择。

但是,如果您想将 Option 视为序列并映射它,您可以这样做,因为 Unit 是一个值:

opt map { v =>
  println(v) // process v (result type is Unit)
} getOrElse {
  println("error")
}

顺便说一句,打印错误是某种“反模式”,因此最好抛出无论如何,一个例外:

opt.getOrElse(throw new SomeException)

Pattern matching is the best choice here.

However, if you want to treat Option as a sequence and to map over it, you can do it, because Unit is a value:

opt map { v =>
  println(v) // process v (result type is Unit)
} getOrElse {
  println("error")
}

By the way, printing an error is some kind of "anti-pattern", so it's better to throw an exception anyway:

opt.getOrElse(throw new SomeException)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文