首页 > 解决方案 > 将 Range 和 StrideTo 转换为 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(以及其他类型),而Rangeis 显然符合Sequence并且它的元素是Int.

奇特的是,如果我用block类似签名的类方法替换,没有任何错误

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()第一个将块作为参数的唯一区别。

标签: swiftgenericscollectionssequencewhere

解决方案


在Swift 论坛的讨论中,披露了以下信息:

  1. 我试图实现的被称为更高等级的多态性,这个大特性还没有添加到 Swift 中。
  2. 可能最简单的解决方案是丢弃泛型并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))
            }
        }
    }
    

推荐阅读