一尘不染

全局函数序列(状态:下一个:)和类型推断

swift

背景和详细信息

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...3let seq2 = 4...6),但是出现了非常奇怪的错误消息提示

错误:对成员’ sequence(first:next:)‘的引用不明确

仅当我Statenext闭包中显式键入注释可变参数及其返回类型时,以上示例才会编译

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:)但是,这不是我希望使用的方式,因为我宁愿在动态应用程序中看到这种方式,在这种应用程序中类型推断应按应有的方式工作,避免了所有显式性。

  • 我们是否打算将sequence(first:next:)函数与上述显式类型注释一起使用?由于inout参数关闭,此功能是否存在某些限制,或者我缺少什么?

阅读 231

收藏
2020-07-07

共1个答案

一尘不染

这看起来像是两个问题的组合。

首先是Swift目前没有任何外部上下文都无法推断多行闭包的类型。但是,这是预期的行为,正如Apple开发人员Jordan
Rose在SR-1570的评论中所证实的那样:

这是正确的行为:Swift不会从多语句闭包的主体中推断参数或返回类型。但是诊断可能会好得多。

因此,从理论上讲,您只需要显式定义传递给sequence()next:参数的闭包的返回类型,因为可以从外部上下文推断出参数的类型(即传递给state:参数的类型):

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()
})

(编辑:现在可以在Swift 3.1中进行编译)


但是,这仍然无法编译-这是由于第二个问题,在第二个问题中,编译器无法推断inoutSwift 3中闭包参数的类型(在Swift
2中不是这种情况)。这是一个可疑的错误,已经提交(请参见SR-1976SR-1811)。

因此,正如您在问题中指出的那样,这意味着(相当不令人满意)您必须显式地注释传递给next:以下内容的完整闭包签名:

let combined = 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()
})
2020-07-07