Расширение протокола Swift с AssociatedType, ограниченным коллекцией, не может использовать нижний индекс

Я пытаюсь написать протокол, который соответствует протоколу коллекции, и он имеет связанный тип - объект и объект свойства.

protocol DDCDataSource: Collection
{
    associatedtype Object
    var object: Object {get set}
}

Я хочу добавить некоторые функциональные возможности по умолчанию для случая, когда Object также соответствует протоколу Collection, а именно просто напрямую возвращать реализацию Object этих требуемых свойств и функций Collection. Кажется, что все это работает, за исключением требования коллекции для нижнего индекса.

Невозможно добавить значение типа "Self.Object" с индексом типа "Self.Object.Index"

extension DDCDataSource where Object: Collection
{
    typealias Index = Object.Index

    var startIndex: Object.Index {
        get {
            return object.startIndex
        }
    }

    var endIndex: Object.Index {
        get {
            return object.endIndex
        }
    }

    subscript(position: Object.Index) -> Element
    {
        return object[position]
    }

    func index(after i: Object.Index) -> Object.Index {
        return object.index(after: i)
    }
}

3 ответа

Решение

Краткий ответ: измените тип возвращаемого значения метода индекса Object.Element

subscript(position: Object.Index) -> Object.Element {
    return object[position]
}

или добавьте псевдоним типа (аналогично тому, как вы это делали для Index тип)

typealias Element = Object.Element

subscript(position: Object.Index) -> Element {
    return object[position]
}

Это заставляет код компилироваться и запускаться как ожидалось.


Пояснение: subscript метод Collection объявлен как

subscript(position: Self.Index) -> Self.Element { get }

где Self.Index а также Self.Element являются ассоциированными типами коллекции. С вашим кодом

subscript(position: Object.Index) -> Element {
    return object[position]
}

компилятор выводит Self.Index быть Object.Index, но нет никакой связи между Self.Element а также Object.Element (который возвращается object[position]). Ошибка становится более очевидной, если вы добавите явное приведение:

subscript(position: Object.Index) -> Element {
    return object[position] as Element
}

Сейчас компилятор жалуется

ошибка: "Self.Object.Element" не конвертируется в "Self.Element"; Вы хотели использовать "как!" заставить опуститься?

Правильное решение - не принудительное приведение, а чтобы компилятор знал, что Self.Element является Object.Element, добавив псевдоним типа или изменив тип возвращаемого значения

subscript(position: Object.Index) -> Object.Element {
    return object[position]
}

так что компилятор выводит DDCDataSource.Element быть Object.Element,


Полный автономный пример: (Swift 4, Xcode 9 beta 6)

(Обратите внимание, что вы можете опустить get ключевое слово для вычисляемых свойств только для чтения.)

protocol DDCDataSource: Collection {
    associatedtype Object
    var object: Object { get set }
}

extension DDCDataSource where Object: Collection {
    var startIndex: Object.Index {
        return object.startIndex
    }

    var endIndex: Object.Index {
        return object.endIndex
    }

    subscript(position: Object.Index) -> Object.Element {
        return object[position]
    }

    func index(after i: Object.Index) -> Object.Index {
        return object.index(after: i)
    }
}

struct MyDataSource: DDCDataSource {
    var object = [1, 2, 3]
}

let mds = MyDataSource()
print(mds[1]) // 2

for x in mds { print(x) } // 1 2 3

Попробуй это:

subscript(position:Object.Index) -> Element
    {
        var element: Element
        guard let elementObject = object[position] else {
            //handle the case of 'object' being 'nil' and exit the current scope
        }
        element = elementObject as! Element

    }

Во-первых, я думаю, что вы должны определить Element,

Во-вторых, вы используете object[position]Объект соответствует коллекции, но он не относится к типам коллекции. Очевидно, это не Array.

Как говорит яблоко: массив соответствует CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg /Decodable / Encodable / ExpressibleByArrayLiteral /MutableCollection /RandomAccessCollection / RangeReplaceableCollection

Я думаю extension DDCDataSource where Object: Array лучше.

И элемент в массиве должен быть Element определены. Просто советы.

Другие вопросы по тегам