Swift演进提案SE-0094在Swift 3.0中实现,引入了全局sequence
函数:
后者声明如下
func sequence<T, State>(state: State, next: @escaping (inout State) -> T?) -> UnfoldSequence<T, State>
并在swift/stdlib/public/core/UnfoldSequence.swift中实施。语言参考提供了以下使用它的示例(请注意缺少显式类型注释)
// Interleave two sequences that yield the same element type sequence(state: (false, seq1.makeIterator(), seq2.makeIterator()), next: { iters in iters.0 = !iters.0 return iters.0 ? iters.1.next() : iters.2.next() })
但是,我不能让上面的示例工作(例如使用let seq1 = 1...3
,let seq2 = 4...6
),但是会出现相当奇怪的错误消息
错误:对成员&{39;
的含糊不清的引用sequence(first:next:)
&#39;
只有当我在State
闭包中显式地键入注释可变next
参数及其返回类型时,上面的示例才会编译
let seq1 = 1...3
let seq2 = 4...6
for i in sequence(state: (false, seq1.makeIterator(), seq2.makeIterator()),
next: { (iters: inout (Bool, ClosedRangeIterator<Int>, ClosedRangeIterator<Int>))
-> Int? in
iters.0 = !iters.0
return iters.0 ? iters.1.next() : iters.2.next()
}) {
print(i)
} // 1 4 2 5 3 6
这不是我希望使用sequence(state:next:)
的方式,但是,我宁愿在即时应用程序中看到它,其中类型推断可以正常工作,避免所有显式。< / p>
sequence(first:next:)
函数与上面的显式类型注释一起使用?由于inout
参数关闭,这个函数是否有一些限制,或者我错过了什么?答案 0 :(得分:2)
这看起来像是两个问题的组合。
首先,Swift目前还没有推断出没有任何外部环境的多线闭包的类型。然而,正如Apple开发人员Jordan Rose在SR-1570的评论中所证实的那样,这是预期的行为:
这是正确的行为:Swift不会从多语句闭包的主体中推断出参数或返回类型。但诊断可能会好很多。
因此理论上,您只需要显式定义传递给sequence()
的{{1}}参数的闭包的返回类型,因为参数类型可以从外部上下文推断出来(即传递给next:
参数的类型):
state:
(编辑:现在在Swift 3.1中编译)
然而,这仍然没有编译 - 这是由于第二个问题,编译器无法推断Swift 3中let seq1 = 1...3
let seq2 = 4...6
let combined = sequence(state: (false, seq1.makeIterator(), seq2.makeIterator()),
next: { iters -> Int? in
iters.0 = !iters.0
return iters.0 ? iters.1.next() : iters.2.next()
})
闭包参数的类型(事实并非如此)在斯威夫特2)。这是一个可疑的错误,已经提交(参见SR-1976和SR-1811)。
因此,正如您在问题中所述,这意味着(非常不满意)您必须明确注释传递给inout
的完整闭包签名:
next:
答案 1 :(得分:1)
但即使承认这是一个错误,你仍然可以使代码看起来更好而不用担心它(在没有测试的情况下键入浏览器,但这样的东西应该有效):
typealias MyTriple = (Bool, ClosedRangeIterator<Int>, ClosedRangeIterator<Int>)
let someTriple : MyTriple = (false, seq1.makeIterator(), seq2.makeIterator())
let combined = sequence(state: someTriple) {
(iters: inout MyTriple) -> Int? in
iters.0 = !iters.0
return iters.0 ? iters.1.next() : iters.2.next()
}