Особые ошибки при преобразовании Range и StrideTo в Sequence - PullRequest
0 голосов
/ 23 ноября 2018

Следующая функция выдает ошибки компилятора :

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 на метод класса с аналогичной сигнатурой, не будет никаких ошибок :

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() в том, что первый принимает блок в качестве параметра.

1 Ответ

0 голосов
/ 05 декабря 2018

Во время обсуждения на форумах 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))
            }
        }
    }
    
...