Swift 全局函数序列(状态:next:)和类型推断 背景与细节
Swift进化方案在Swift 3.0中实施,引入了全局Swift 全局函数序列(状态:next:)和类型推断 背景与细节,swift,swift3,sequence,Swift,Swift3,Sequence,Swift进化方案在Swift 3.0中实施,引入了全局序列功能: 后者声明如下 但是,我无法使上述示例正常工作(例如,使用让seq1=1…3,让seq2=4…6),但会出现一条奇怪的错误消息 错误:对成员“序列”(第一个:下一个:)的引用不明确 只有当我在next闭包中显式地对可变State参数以及它的返回类型进行注释时,上面的示例才会编译 let seq1 = 1...3 let seq2 = 4...6 for i in sequence(state: (false, seq1.
序列功能:
后者声明如下
但是,我无法使上述示例正常工作(例如,使用让seq1=1…3
,让seq2=4…6
),但会出现一条奇怪的错误消息
错误:对成员“序列”(第一个:下一个:)
的引用不明确
只有当我在next
闭包中显式地对可变State
参数以及它的返回类型进行注释时,上面的示例才会编译
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
让seq1=1…3
设seq2=4…6
对于序列中的i(状态:(false,seq1.makeIterator(),seq2.makeIterator()),
下一步:{(iters:inout(Bool,ClosedRangeIterator,ClosedRangeIterator))
->Int?in
iters.0=!iters.0
返回iters.0?iters.1.next():iters.2.next()
}) {
印刷品(一)
} // 1 4 2 5 3 6
这不是我希望使用的序列(state:next:)
,但是,我更希望在即时应用程序中看到它,在这种应用程序中,类型推断可以正常工作,避免所有的明确性
问题:
- 我们是否打算将
序列(first:next:)
函数与上面的显式类型注释一起使用?由于inout
参数闭包,此函数是否有一些限制,或者我是否缺少了什么
这看起来是两个问题的结合
首先,Swift目前没有推断出没有任何外部上下文的多行闭包的类型。然而,正如苹果开发商Jordan Rose在以下评论中所证实的,这是有意的行为:
这是正确的行为:Swift不会从多语句闭包的主体中推断参数或返回类型。但诊断可能会好得多
因此,理论上,您只需要显式定义传递给
sequence()
的next:
参数的闭包的返回类型,因为可以从外部上下文推断参数类型(即传递到状态:
参数的类型):
(编辑:现在在Swift 3.1中编译)
但是,这仍然无法编译–这是由于第二个问题,即编译器无法推断Swift 3中inout
闭包参数的类型(Swift 2中的情况并非如此)。这是一个可疑的bug,已经存档(请参见&)
因此,正如您在问题中所注意到的,这意味着(非常不令人满意)您必须显式地注释传递给下一步:
的完整闭包签名:
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()
})
let combined=sequence(状态:(false,seq1.makeIterator(),seq2.makeIterator()),
下一步:{(iters:inout(Bool,ClosedRangeIterator,ClosedRangeIterator))->Int?in
iters.0=!iters.0
返回iters.0?iters.1.next():iters.2.next()
})
但即使承认这是一个bug,您仍然可以让代码看起来更漂亮,而不用担心它(在浏览器中键入而不进行测试,但类似的东西应该可以工作):
typealias MyTriple=(Bool、ClosedRangeIterator、ClosedRangeIterator)
让sometree:MyTriple=(false,seq1.makeIterator(),seq2.makeIterator())
设combined=序列(状态:sometree){
(iters:inout MyTriple)->Int?in
iters.0=!iters.0
返回iters.0?iters.1.next():iters.2.next()
}
@Hamish谢谢,该错误报告将符合此行为。感谢关于泛型专门化的另一点,我正在删除这一点(由于其他原因)!至少我认为序列的ref.docs(state:next:)
应该更新,以包含inout
参数的显式注释,如果仅仅依靠文档(而不是广泛的贡献者知识!),那么尝试使用该函数会非常混乱你可能会在你的评论中发布信息作为答案,它似乎涵盖了解释“限制”的大部分内容在我的问题中询问有关的问题。我已经继续并发布了一个答案:)但不幸的是,除了我在最初的评论中所说的以外,我还没有真正发现其他问题。我在书的这一部分末尾有一个斐波那契实现,我不得不使用显式类型注释。但我不介意。:)[顺便说一句,我编辑了你的标题,因为原来q.实际上只是关于类型推断的问题]@matt谢谢你的编辑和回答!另外,我肯定会建议苹果公司在未编译的文档示例上提交一个bug。好吧,但公平一点。您可以使用类型别名和尾随闭包语法,使代码看起来更好。你有点故意让它看起来很糟糕。@matt我同意尾随闭包语法可以让它看起来稍微好一点(尽管在这种情况下我实际上有点偏爱使用next:
参数名,因为(至少对我来说)它增加了清晰度,还使Xcode与状态:
参数很好地对齐)。如果要使用相同的状态类型多次调用序列(state:next:)
,那么typealias
是个好主意,尽管如果只使用一次,IMO似乎有些多余。哦,我同意这是我们不应该做的事情。
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
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()
})
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()
})
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()
}