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

时间:2016-10-23 10:20:50

标签: swift swift3 sequence

背景&详情

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),但是会出现相当奇怪的错误消息

  

错误:对成员&{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参数关闭,这个函数是否有一些限制,或者我错过了什么?

2 个答案:

答案 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-1976SR-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()
}