首页 > 解决方案 > 快速惰性序列 - 为什么在引入定义时编译器会抱怨

问题描述

我正在使用 Ints 的惰性序列:

let a = [1,2,3].lazy

我首先定义一个 Ints 流,如下所示:

protocol Stream: LazySequenceProtocol where Element == Int {}
extension LazySequence:       Stream  where Element == Int {}
extension LazyMapSequence:    Stream  where Element == Int {}

我将用流做复杂的事情,但为了演示这个问题,我会保持简单。我扩展了流以允许递增值:

extension Stream {
  func increment() -> some Stream {
    map{ value in
      return value + 1
    }
  }
}
print(Array(a.increment())) // Prints [2, 3, 4]

请注意, a.increment() 是一个惰性函数,因此需要被 Array() 包围才能将结果转换为数组以进行打印。

还要注意使用 Swift 5.1 中引入的单词“some”来表示不透明类型,并允许我们以这种方式实现流 - 如果没有不透明类型,这并不是那么简单。

而且我可以做更多有趣的事情,比如在自身后面插入 10 倍的值:

extension Stream {
  func insert10x() -> some Stream {
    flatMap{ value in
      return [value, value*10]
    }
  }
}
print(Array(a.insert10x()))             // Prints [1, 10, 2, 20, 3, 30]

这意味着我可以开始以不同的方式组合我的函数:

print(Array(a.insert10x().increment())) // Prints [2, 11, 3, 21, 4, 31]
print(Array(a.increment().insert10x())) // Prints [2, 20, 3, 30, 4, 40]

以上所有内容都按预期编译和工作。

但是......如果我引入一个额外的行,例如下面的“let multiplier = 10”,那么我会得到编译器错误:

extension Stream {
  func insert10xVersion2() -> some Stream {
    flatMap{ value in                      // Error 1
      let multiplier = 10
      return [value, value * multiplier]   // Error 2
    }
  }
}
print(Array(a.insert10xVersion2()))             // Should prints [1, 10, 2, 20, 3, 30]

两个编译器错误:

错误 1: 不推荐使用“flatMap”:对于闭包返回可选值的情况,请使用 compactMap(_:)。使用 'compactMap(_:) 代替。

错误 2: 无法将类型“[Int]”的返回表达式转换为返回类型“Int?”

这两个错误似乎都表明编译器已决定 flatMap 正在处理可选项,因此鼓励使用 compactMap 代替。

但我会认为这应该产生与第一个版本相同的结果!

也许这是一个编译器错误,但我想我先在这里检查一下是否有人能看到我的代码有问题?

标签: swiftflatmaplazy-sequences

解决方案


推荐阅读