将 Range 和 StrideTo 转换为 Sequence 时出现特殊错误
Peculiar errors while converting Range and StrideTo into Sequence
以下函数产生编译器错误:
func iterateColumnsAlongGravity<S: Sequence>(using block: (_ indexes: S) -> ())
where S.Element == Int {
switch gravityDirection {
case .bot:
for i in stride(from: 0, to: w * h, by: h) {
// 'Range<Int>' is not convertible to 'S'
block(i..<(i + h))
}
case .top:
for i in stride(from: 0, to: w * h, by: h) {
// 'ReversedCollection<(Range<Int>)>' is not convertible to 'S'
block((i..<(i + h)).reversed())
}
case .left:
for y in 0..<h {
let indexes = stride(from: y, to: w * h, by: h).reversed()
// '([Int]) -> ()' is not convertible to '(S) -> ()'
block(indexes)
}
case .right:
for y in 0..<h {
// '(StrideTo<Int>) -> ()' is not convertible to '(S) -> ()'
let indexes = stride(from: y, to: w * h, by: h)
block(indexes)
}
}
}
我不明白为什么 编译器不将 Range<Int>
转换为 S
(以及其他类型),而 Range
显然符合Sequence
,它的元素是Int
。
更奇特,如果我将block
替换为具有类似签名的class方法,没有任何错误:
func printIntSequence<S: Sequence>(_ s: S) where S.Element == Int {
for i in s {
print(i)
}
}
func typeConversionTest() {
switch gravityDirection {
case .bot:
for i in stride(from: 0, to: w * h, by: h) {
printIntSequence(i..<(i + h))
}
case .top:
for i in stride(from: 0, to: w * h, by: h) {
printIntSequence((i..<(i + h)).reversed())
}
case .left:
for y in 0..<h {
let indexes = stride(from: y, to: w * h, by: h).reversed()
printIntSequence(indexes)
}
case .right:
for y in 0..<h {
let indexes = stride(from: y, to: w * h, by: h)
printIntSequence(indexes)
}
}
}
iterateColumnsAlongGravity(using:)
和typeConversionTest()
的唯一区别是第一个以块为参数。
在 the discussion 期间 Swift 论坛上透露了以下信息:
- 我试图实现的是所谓的高阶多态性,这个重要的特性还没有添加到 Swift。
可能最简单的解决方案是丢弃泛型并在此处使用 StrideTo<Int>
。
func iterateColumnsAlongGravity(using block: (_ indexes: StrideTo<Int>) -> ()) {
switch gravityDirection {
case .bot:
for i in stride(from: 0, to: w * h, by: h) {
block(stride(from: i, to: i + h, by: 1))
}
case .top:
for i in stride(from: 0, to: w * h, by: h) {
block(stride(from: i + h - h, to: i - h, by: -1))
}
case .left:
for y in 0..<h {
block(stride(from: (w - 1) * h + y, to: -1, by: -h))
}
case .right:
for y in 0..<h {
block(stride(from: y, to: w * h, by: h))
}
}
}
以下函数产生编译器错误:
func iterateColumnsAlongGravity<S: Sequence>(using block: (_ indexes: S) -> ())
where S.Element == Int {
switch gravityDirection {
case .bot:
for i in stride(from: 0, to: w * h, by: h) {
// 'Range<Int>' is not convertible to 'S'
block(i..<(i + h))
}
case .top:
for i in stride(from: 0, to: w * h, by: h) {
// 'ReversedCollection<(Range<Int>)>' is not convertible to 'S'
block((i..<(i + h)).reversed())
}
case .left:
for y in 0..<h {
let indexes = stride(from: y, to: w * h, by: h).reversed()
// '([Int]) -> ()' is not convertible to '(S) -> ()'
block(indexes)
}
case .right:
for y in 0..<h {
// '(StrideTo<Int>) -> ()' is not convertible to '(S) -> ()'
let indexes = stride(from: y, to: w * h, by: h)
block(indexes)
}
}
}
我不明白为什么 编译器不将 Range<Int>
转换为 S
(以及其他类型),而 Range
显然符合Sequence
,它的元素是Int
。
更奇特,如果我将block
替换为具有类似签名的class方法,没有任何错误:
func printIntSequence<S: Sequence>(_ s: S) where S.Element == Int {
for i in s {
print(i)
}
}
func typeConversionTest() {
switch gravityDirection {
case .bot:
for i in stride(from: 0, to: w * h, by: h) {
printIntSequence(i..<(i + h))
}
case .top:
for i in stride(from: 0, to: w * h, by: h) {
printIntSequence((i..<(i + h)).reversed())
}
case .left:
for y in 0..<h {
let indexes = stride(from: y, to: w * h, by: h).reversed()
printIntSequence(indexes)
}
case .right:
for y in 0..<h {
let indexes = stride(from: y, to: w * h, by: h)
printIntSequence(indexes)
}
}
}
iterateColumnsAlongGravity(using:)
和typeConversionTest()
的唯一区别是第一个以块为参数。
在 the discussion 期间 Swift 论坛上透露了以下信息:
- 我试图实现的是所谓的高阶多态性,这个重要的特性还没有添加到 Swift。
可能最简单的解决方案是丢弃泛型并在此处使用
StrideTo<Int>
。func iterateColumnsAlongGravity(using block: (_ indexes: StrideTo<Int>) -> ()) { switch gravityDirection { case .bot: for i in stride(from: 0, to: w * h, by: h) { block(stride(from: i, to: i + h, by: 1)) } case .top: for i in stride(from: 0, to: w * h, by: h) { block(stride(from: i + h - h, to: i - h, by: -1)) } case .left: for y in 0..<h { block(stride(from: (w - 1) * h + y, to: -1, by: -h)) } case .right: for y in 0..<h { block(stride(from: y, to: w * h, by: h)) } } }