【问题标题】:Scala Option.fold Behaves differently in and out of functionScala Option.fold 在函数内外表现不同
【发布时间】:2021-07-20 14:09:18
【问题描述】:

取简单函数:

def makeUpper(input: Option[String]): String = 
    input.fold("b"){ _.toUpperCase }

makeUpper(Some("a"))   // A
makeUpper(None)        // b

这符合预期。

现在,相同的代码,但在函数之外:

Some("a").fold("b"){ _.toUpperCase }   // A
None.fold("b"){ _.toUpperCase }        // error: value toUpperCase is not a member of Nothing

注意:

Option.empty[String].fold("b"){ _.toUpperCase }   // b

问题:

  1. 为什么会有不同的行为?为什么会出现函数外的错误?

函数是否将输入 None 转换为“确定的” Option.empty[String]?

  1. 处理返回 Option(Some 或 None)的函数返回的正确方法是什么...我们是否总是必须在另一个函数中处理返回值以避免上述问题?

我错过了什么?

【问题讨论】:

  • 问题是你永远不应该有一个类型为None.typeSome 的值总是Option[X] - 如果你知道你有一个None,为什么还要打电话给fold 如果你知道它总是会调用isEmpty 参数。

标签: scala optional


【解决方案1】:

Scala 编译器可以推断类型。

由于你已经将函数参数input定义为Option[String],即使你传递了None,编译器也知道它是一个Option[String]并适当地键入它。

这是一种什么样的做法,

val none: Option[String] = None
none.fold("b"){ _.toUpperCase }

或者这个,

(None: Option[String]).fold("b"){ _.toUpperCase }

当直接使用None 而不使用任何额外信息时,编译器仍会尝试仅使用None extends Option[Nothing] 的可用信息来推断最佳猜测,因此将其视为Option[Nothing]。相当于,

val none: Option[Nothing] = None
none.fold("b"){ _.toUpperCase }

或者这个,

(None: Option[Nothing]).fold("b"){ _.toUpperCase }

请注意,在这种情况下,与 String 没有任何关系。

只要你在一个地方告诉你想要的类型来帮助编译器。它将能够推断出其他相关地点的预期类型。

scala> val noneIntOpt = noneStringOpt
// val noneIntOpt: Option[String] = None

scala> val noneIntOpt = noneStringOpt.map(_.length)
// val noneIntOpt: Option[Int] = None

【讨论】:

  • 你也可以使用Option.empty[String]
  • 是的,但问题只是关于None。这个问题也与方差有关,但我决定在没有方差相关细节的情况下回答以保持简单。
【解决方案2】:

None 定义为:

case object None extends Option[Nothing]

因此,当您在None 的“内容”上调用方法时,您是在对Nothing 类型的值调用方法。这种类型没有方法toUpperCase,所以会报错。

但是Nothing 兼容所有类型,Option 与其类型参数协变,所以Option[Nothing] 兼容Option[String]。这就是为什么 None 可以传递给您的 makeUpper 方法的原因。一旦知道内容的类型是String,就可以对其调用toUpperCase方法。

【讨论】:

    猜你喜欢
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多