Разница между расширением и прямым вызовом для протокола - PullRequest
0 голосов
/ 19 ноября 2018

Я получил этот код:

protocol Protocol {
    var id: Int { get }
}

extension Array where Element: Protocol {
    func contains(_protocol: Protocol) -> Bool {
        return contains(where: { $0.id == _protocol.id })
    }
}

class Class {
    func method<T: Protocol>(_protocol: T) {
        var arr = [Protocol]()

        // Does compile
        let contains = arr.contains(where: { $0.id == _protocol.id })

        // Doens't compile
        arr.contains(_protocol: _protocol)
    }
}

Почему строка кода не компилируется, где я прокомментировал «Не компилировать»?Это ошибка:

Incorrect argument label in call (have '_protocol:', expected 'where:')

Когда я изменяю имя метода в расширении на что-то другое, например containz (и, конечно, меняю имя метода, который вызывает его на containz), япоявляется эта ошибка, когда я пытаюсь вызвать ее:

Using 'Protocol' as a concrete type conforming to protocol 'Protocol' is not supported

Но почему она не работает, когда я пытаюсь вызвать ее через расширение, но работает, когда я создаю функцию в расширении напрямую?На самом деле я не вижу никакой разницы.

1 Ответ

0 голосов
/ 19 ноября 2018

Я согласен с Мэттом, что основной ответ - Протокол не соответствует самому себе? , но, вероятно, все равно стоит ответить, так как в этом случае ответ очень прост.Во-первых, прочитайте связанный вопрос о том, почему [Protocol] не работает так, как вы думаете (особенно ответ Хэмиша, который намного обширнее, чем принятый мной ответ).[Protocol] не соответствует предложению where Element: Protocol, поскольку Protocol не является конкретным типом, который соответствует Protocol (потому что это не конкретный тип).

Но вам не нужно [Protocol]Вот.У вас есть T: Protocol, поэтому вы можете (и должны) просто использовать это:

var arr = [T]()

С этим изменением все остальное должно работать так, как вы ожидаете, потому что T - это конкретный тип, соответствующий протоколу.

...