带有选项的scala编程实践
scala programming practice with option
可能是我的设计有缺陷(很可能是),但我一直在思考 Option
在 Scala
中的使用方式,对此我不是很满意。假设我有 3 种方法可以这样互相调用:
def A(): reads a file and returns something
def B(): returns something
def C(): Side effect (writes into DB)
和 C()
调用 B()
,然后 B()
调用 A()
现在,由于 A() 依赖于 I/O
操作,我必须处理异常以及 return 和 Option
否则它不会编译(如果 A()
没有 return 任何东西)。由于 B()
从 A()
接收到一个 Option
并且它必须 return 一些东西,它被绑定到 return 另一个 Option
到 C()
.因此,您可以想象我的代码充满了 match/case Some/case None
(不要总是使用 getOrElse()
)。而且,如果 C()
依赖于其他一些方法,这些方法也 return Option
,你会害怕查看 C()
的定义。
那么,我是不是漏掉了什么?或者我的设计有多大缺陷?我该如何改进它?
在类型 Option
上使用 match
/case
通常在您想要丢弃 Option
并在处理 [=15= 之后产生一些值时很有用] 但如果您有 None
,则为同一类型的不同值。 (就个人而言,我通常发现 fold
对于这种情况更干净。)
另一方面,如果您要传递 Option
,那么还有其他方法可以解决。
def a():Option[DataType] = {/*read new data or fail*/}
def b(): Optioon[DataType] = {
... //some setup
a().map{ inData =>
... //inData is real, process it for output
}
}
def c():Unit = {
... //some setup
b().foreach{ outData =>
... //outData is real, write it to DB
}
}
am I missing something?
Option
是一个设计决定,但可以有其他设计决定。即当您想描述由 API 编辑的错误 return 时会发生什么? Option
只能告诉你两种状态,要么我成功读取了一个值,要么我失败了。但有时你真的很想知道 为什么 你失败了。或者更多,如果我 return None
,是因为文件不存在还是因为我因异常而失败(即我没有读取文件的权限?)。
无论您选择哪条道路,您通常都会处理一个或多个影响。 Option
就是这样一种效果,它表示部分函数,即此操作可能不会产生结果。正如其他人所说,虽然使用 Option
的模式匹配是一种处理它的方法,但还有其他操作可以减少冗长。
例如,如果您想在值存在的情况下调用一个操作,在值不存在的情况下调用另一个操作,并且它们都具有相同的 return 类型,您可以使用 Option.fold
:
scala> val maybeValue = Some(1)
maybeValue: Some[Int] = Some(1)
scala> maybeValue.fold(0)(x => x + 1)
res0: Int = 2
一般有many such combinators defined on Option
等效果,一开始可能觉得笨重,后来逐渐深入人心,当你想一个接一个地组合操作时,你就会看到它们的真正威力.
可能是我的设计有缺陷(很可能是),但我一直在思考 Option
在 Scala
中的使用方式,对此我不是很满意。假设我有 3 种方法可以这样互相调用:
def A(): reads a file and returns something
def B(): returns something
def C(): Side effect (writes into DB)
和 C()
调用 B()
,然后 B()
调用 A()
现在,由于 A() 依赖于 I/O
操作,我必须处理异常以及 return 和 Option
否则它不会编译(如果 A()
没有 return 任何东西)。由于 B()
从 A()
接收到一个 Option
并且它必须 return 一些东西,它被绑定到 return 另一个 Option
到 C()
.因此,您可以想象我的代码充满了 match/case Some/case None
(不要总是使用 getOrElse()
)。而且,如果 C()
依赖于其他一些方法,这些方法也 return Option
,你会害怕查看 C()
的定义。
那么,我是不是漏掉了什么?或者我的设计有多大缺陷?我该如何改进它?
在类型 Option
上使用 match
/case
通常在您想要丢弃 Option
并在处理 [=15= 之后产生一些值时很有用] 但如果您有 None
,则为同一类型的不同值。 (就个人而言,我通常发现 fold
对于这种情况更干净。)
另一方面,如果您要传递 Option
,那么还有其他方法可以解决。
def a():Option[DataType] = {/*read new data or fail*/}
def b(): Optioon[DataType] = {
... //some setup
a().map{ inData =>
... //inData is real, process it for output
}
}
def c():Unit = {
... //some setup
b().foreach{ outData =>
... //outData is real, write it to DB
}
}
am I missing something?
Option
是一个设计决定,但可以有其他设计决定。即当您想描述由 API 编辑的错误 return 时会发生什么? Option
只能告诉你两种状态,要么我成功读取了一个值,要么我失败了。但有时你真的很想知道 为什么 你失败了。或者更多,如果我 return None
,是因为文件不存在还是因为我因异常而失败(即我没有读取文件的权限?)。
无论您选择哪条道路,您通常都会处理一个或多个影响。 Option
就是这样一种效果,它表示部分函数,即此操作可能不会产生结果。正如其他人所说,虽然使用 Option
的模式匹配是一种处理它的方法,但还有其他操作可以减少冗长。
例如,如果您想在值存在的情况下调用一个操作,在值不存在的情况下调用另一个操作,并且它们都具有相同的 return 类型,您可以使用 Option.fold
:
scala> val maybeValue = Some(1)
maybeValue: Some[Int] = Some(1)
scala> maybeValue.fold(0)(x => x + 1)
res0: Int = 2
一般有many such combinators defined on Option
等效果,一开始可能觉得笨重,后来逐渐深入人心,当你想一个接一个地组合操作时,你就会看到它们的真正威力.