Extension Array & ArraySlice


#1

Приветствую! Есть несколько функций, которые хотелось бы реализовать в виде extension как для Array, так и для ArraySlice. Чтобы не пришлось копипастить один и тот же код функций, хотелось бы одновременно расширить Array и ArraySlice. Как это можно сделать? В лоб прописать extension Array, ArraySlice - не получилось.


#2

Расширить протокол (общий для Array и ArraySlice) Collection:

extension Collection where Element == Int {
    func myPrint() {
        print(self)
    }
}

var arr = [1, 2, 3]

arr.myPrint()

arr[1...].myPrint()

#3

Спасибо. Добавил еще вот эти субскрипты, чтобы можно было отбирать элементы внутри функций внутри расширения:

subscript(index: Int) -> MyStruct {
    return Array(self)[index]
}

subscript(range: CountableClosedRange<Int>) -> [MyStruct] {
    return Array(self)[range]
}

Теперь получается обращаться к элементу/ам так: self[0] или self[1…2]. Но self[1…] не работает - Cannot subscript a value of type 'Self' with an index of type 'CountablePartialRangeFrom<Int>'. Непринципиально, но может есть какое-то более правильное решение?


#4

Переопределять сабскрипты плохая идея.

Если будете писать прям в лоб, то он будет вызывать сам себя до бесконечности:

extension Collection where Index == Int, Element == String {
    subscript(range: CountablePartialRangeFrom<Index>) -> [Element] {
        print(range)
        return Array(self[range])
    }
}

var arr = ["A", "B", "C"]

print(arr[1...])

Что бы это заработало нужно внутри вашего сабскрипта вызывать встроенный, для этого нужно указать тип возвращаемого значения:

extension Collection where Index == Int, Element == String {
    subscript(range: CountablePartialRangeFrom<Index>) -> [Element] {
        let result: SubSequence = self[range]
        return Array(result)
    }
}

var arr = ["A", "B", "C"]

print(arr[1...])

Но лучше пишите методы их проще запомнить и методы имеют названия, чем себя самодокументируют :slight_smile:

extension Collection where Index == Int, Element == String {
    func get(_ range: CountablePartialRangeFrom<Index>) -> [Element] {
        return Array(self[range])
    }
}

var arr = ["A", "B", "C"]

print(arr.get(1...))

#5

В моем случае лучше не через метод, а через сабскрипты, например myStruct[0…1].isHigher - isHigher рассчитываемая переменная Bool, которая принимает массив и делает выводы:)

Получился вот такой код, все работает нормально:

extension Collection where Index == Int, Element == MyStruct {
    
    subscript(index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
    
    subscript(range: CountableClosedRange<Index>) -> [Element]? {
        guard indices.contains(range.lowerBound), indices.contains(range.upperBound) else { return nil }
        let subSequence: SubSequence = self[range]
        return Array(subSequence)
    }

    subscript(range: CountablePartialRangeFrom<Index>) -> [Element]? {
        guard indices.contains(range.lowerBound) else { return nil }
        let subSequence: SubSequence = self[range]
        return Array(subSequence)
    }
    
    //...
    }

Вот только не пойму, почему первый сабскрипт никогда не вызывается. Если в массиве 100 элементов, а я вызову myStruct[200], то вместо nil получу run time error.