Either 是你在 Swift 中已经知道的类型之一,但它专门用于某些值。
这就是它
enum Either<Left, Right> {
case left(Left)
case right(Right)
}
Slo 它是一个具有两种情况的枚举。这至少应该让你想起两件事。通常 right
的情况与 good
(好)或 success
(成功)或 dextra
(拉丁语“右”)相关联。另一方面,left
的情况用于 bad
(坏)、failure
(失败)、error
(错误),或者你可以说是 sinistra
(拉丁语“左”)。
至少 Swift 中常见的两种类型是 Either
的特化。
你可以看看 Optional,并将 left
与 none 情况匹配。你也可以看看 Result,并将 failure 与 left
情况匹配。
所以这里你有一个更通用的类型可以使用。它不仅在你需要验证内容时有用。而且在需要返回不同类型时也很有用。
为了让生活更轻松一点,这里定义了一些辅助属性。
用于逻辑检查的便捷属性。
var isLeft : Bool // true if `left` case
var isRight: Bool // true if `right` case
当你想获取一个值,但可以处理 optional 时。
var right: Right?
var left : Left?
看看 OptionalAPI,了解如何愉快地使用 Optional。
func map<R>(_ transform: (Right) -> R) -> Either<Left,R>
这是一个函数,它接受一个函数,该函数期望 Right
的一个实例,并生成一个新的 Either<Left, R>
实例。类型 R
意味着 NewRight
,但被缩写了。
Either 对其 right 值进行了一些特殊处理。这类似于 Result 和 Optional 如何处理它们自身的一些情况。
这意味着如果你想 map
一个 Either
,那么默认情况下你将被赋予一个 Right
类型的实例。
所以如果你有
func increment(_ i: Int) -> Int { i + 1 }
let right = Either<String,Int>.right(42)
right
.map(increment) // .right(43)
最终结果是一个新的 Either<String,Int>
实例,它的 right
情况持有 43
。对 left 做同样的事情将不会有任何效果。
let left = Either<String,Int>.left("I'm left")
left
.map(increment) // .left("I'm left")
func mapRight<R>(_ transform: (Right) -> R) -> Either<Left, R>
你可以显式地调用 rightMap
,它只是 map
的一个包装器。
func mapLeft<L>(_ transform: (Left) -> L) -> Either<L, Right>
但是,如果你想转换一个 left
值,你可以使用 leftMap
。与 right 相同的故事,但针对 left。
left
.map({ $0.uppercased() }) // .left("I'M LEFT")
func biMap<L,R>( _ leftTransform: (Left) -> L,
_ rightTransform: (Right) -> R)
-> Either<L, R>
这个函数接受另外两个函数作为参数。“Left” 是left 转换,“right” 是 right 转换。这会产生一个新的 Either<L,R>
实例。
这一个 map
结合了 leftMap
和 rightMap
。更常见的名称是 biMap
,但我希望它在 IDE 中方便使用,你可以开始输入 map 并查看那里有什么。
当你想将这些转换组合成一个语句时,可以使用这个 biMap
right
.biMap({ $0.uppercased() }, increment) // .right(43)
left
.biMap({ $0.uppercased() }, increment) // .left("I'M LEFT")
与上面的 map 相同,但有一个区别。
func flatMap<R>(
_ transform: (Right) -> Either<Left, R>
) -> Either<Left, R>
func flatMapLeft<L>(
_ transform: (Left) -> Either<L, Right>
) -> Either<L, Right>
这次转换函数返回另一个 Either。这将导致一个 Either Either,例如 Either<Left, Either<Left, R>>
。因此,使用这个 flatMap(或者你可以找到的另一个名称 bind
),你可以移除一层嵌套。
作为一个旁注,每当你使用 flatMap
时,你都在进行可怕的 monadic 计算。你曾经在 optionals 上调用 flatMap
,并且一切都很好。是的,Optional 是一个 Monad
。如果你想了解更多,你可以 Google 它,只是不要想太多,你会没事的 😎
func either<L,R,T>(
_ leftTransform: @escaping (L) -> T,
_ rightTransform: @escaping (R) -> T) -> (Either<L,R>) -> T
这可能不是很常见,但它是一个返回另一个函数的函数。它的工作方式是你首先提供两个函数。“Left 转换” 知道如何给定一个 L
来产生 T
。“Right 转换” 知道如何给定一个 R
来产生 T
。
下一步是返回的函数。这个函数期望一个 Either<L,R>
,当你提供这个 either 的一个实例时,它将产生一个 T
的实例。
func lefts<L,R>(_ eithers: [Either<L,R>] ) -> [L]
我猜类型说明了一切。给这个函数一个 either 数组,作为回报,你将得到一个 L
的数组。
func rights<L,R>(_ eithers: [Either<L,R>] ) -> [R]
我猜类型说明了一切。给这个函数一个 either 数组,作为回报,你将得到一个 R
的数组。
返回一个元组,其中包含 left
/第一个数组中的所有 L
值。以及 right
/第二个数组中的所有 R
值。
let eithers: [Either<String,Int>] =
[ .left("A"),
.right(42),
.left("B"),
.right(24) ]
let (lefts, rights) = partitionEithers(eithers)
lefts // ["A", "B"]
rights // [42, 24]
如果你懂 🇵🇱 波兰语,那么你可以查看这个 YT 播放列表 Either - Monada Either w Swift
这个项目是 🐇🕳 Rabbit Hole Packages Collection 的一部分