为什么要创建一个参数类型为'Nothing =>的map函数? U`似乎有用吗?

时间:2017-01-06 17:57:41

标签: scala parameters nothing

我正在编写使用API​​的Scala代码,其中对API的调用可以成功,失败或返回异常。我试图让ApiCallResult monad代表这个,我试图使用Nothing类型,以便将失败和异常情况视为任何{{的子类型1}}类型,类似于None或Nil。到目前为止我的工作似乎有效,但我在ApiCallResultmap函数中使用Nothing让我很困惑。以下是flatMap实现的简要示例:

map

因此,它似乎按照我的意图使用 sealed trait ApiCallResult[+T] { def map[U]( f: T => U ): ApiCallResult[U] } case class ResponseException(exception: APICallExceptionReturn) extends ApiCallResult[Nothing] { override def map[U]( f: Nothing => U ) = this } case object ResponseFailure extends ApiCallResult[Nothing] { override def map[U]( f: Nothing => U ) = ResponseFailure } case class ResponseSuccess[T](payload: T) extends ApiCallResult[T] { override def map[U]( f: T => U ) = ResponseSuccess( f(payload) ) } val s: ApiCallResult[String] = ResponseSuccess("foo") s.map( _.size ) // evaluates to ResponseSuccess(3) val t: ApiCallResult[String] = ResponseFailure t.map( _.size ) // evaluates to ResponseFailure 操作成功的结果,但不改变地传递失败和异常。但是,使用Nothing作为输入参数的类型对我没有意义,因为没有Nothing类型的实例。示例中的map函数的类型为_.size,如何将其安全地传递给期望String => Int的内容?这里到底发生了什么?

我还注意到Scala标准库通过让它从Option继承Nothing => U函数来实现None时避免了这个问题。这只会进一步加深我的感觉,我在某种程度上做了一些可怕的错误。

2 个答案:

答案 0 :(得分:2)

有三件事情正在调整以实现这一点,所有这些都与底部类型的协方差和逆变有关:

  1. Nothing是所有类型的底部类型,例如每种类型都是它的超级。
  2. Function1[-T, +R]的类型签名,表示它接受T的超类型的任何类型,并返回R为超级的任何类型。
  3. 类型ApiCallResult[+R]表示U超出R的任何类型U都有效。
  4. 因此任何类型都是super Nothing意味着任何参数类型都是有效的,并且您返回Nothing类型内容的事实是有效的返回类型。

答案 1 :(得分:0)

我建议你不要在大多数时间区分失败和异常。

type ApiCallResult[+T] = Try[T]
case class ApiFailure() extends Throwable

val s: ApiCallResult[String] = Success("this is a string")

s.map(_.size)

val t: ApiCallResult[String] = Failure(new ApiFailure)
t.map(_.size)

要获取失败,请使用match选择结果:

t match {
case Success(s) =>
case Failure(af: ApiFailure) =>
case Failure(x) =>
}