Массив с элементами протокола не может вызывать метод расширения массива - PullRequest
0 голосов
/ 20 февраля 2019

Я хочу, чтобы массив с элементами протокола вызывал метод расширения массива.Код на игровой площадке получает ошибку:

ошибка: тип 'ObjectProtocol' не соответствует протоколу 'Equatable'

Код:

extension Array {
    func good() {
    }
}

protocol ObjectProtocol {

}

extension ObjectProtocol where Self: Equatable  {
   func isEqualTo(_ other: ObjectProtocol) -> Bool {
       guard let otherX = other as? Self else { return false }
       return self == otherX
   }
}

extension Array where Element: Equatable {
    func bad() {}
}

var protocolArray = [ObjectProtocol]()
var array = [1,3,2,5]

array.good() // OK
array.bad() // OK

protocolArray.good() // OK
protocolArray.bad() // error: error: type 'ObjectProtocol' does not conform to protocol 'Equatable'

Есть ли способ добиться этого?

Ответы [ 3 ]

0 голосов
/ 20 февраля 2019

Функция, реализованная в вашем расширении Array, доступна только для экваториальных типов.Функция, реализованная в вашем расширении ObjectProtocol, доступна только для экваторируемых типов, но это не означает, что объект, соответствующий ObjectProtocol, будет также соответствовать Equatable.Для этого вы можете сделать что-то вроде этого:

class Custom<T: ObjectProtocol & Equatable>{
    var array = [T]()

    func doStuff(){
    array.bad()
    }
}
0 голосов
/ 20 февраля 2019

Если вы посмотрите на свою ошибку, это говорит само за себя

ошибка: тип 'ObjectProtocol' не соответствует протоколу 'Equatable'

In ObjectProtocol *Расширение 1008 * Вы добавляете ограничение, которое Self должно соответствовать Equatable.

Вот исправление:

protocol ObjectProtocol {}

extension ObjectProtocol where Self: Equatable  {
    func isEqualTo(_ other: ObjectProtocol) -> Bool {
        guard let otherX = other as? Self else { return false }
        return self == otherX
    }
}

extension Array where Element: Equatable {
    func bad() {
        print("I am bad")
    }
}

extension Array {
    func good() {
        print("I am good")
    }
}
// I have added a custom Type `Friend` and confirm it to the `ObjectProtocol` and Equatable
struct Friends: ObjectProtocol, Equatable{
    var years = 10
}

var protocolArray = [Friends]()
//protocolArray.append(Friends(name: 29))
//protocolArray.append(Friends(name: 50))
var array = [1, 3, 2, 5]

array.good() // OK
array.bad() // OK

protocolArray.good() // OK
protocolArray.bad() // It will work now

0 голосов
/ 20 февраля 2019

Ваше соответствие Equatable является версией Objective-C, а не версией Swift.

protocol FoobarProtocol: Equatable {}

extension FoobarProtocol {
    public static func == (lhs: Self, rhs: Self) -> Bool {
        return true // do something useful
    }
}

Ваш вопрос касается протоколов как Array элементов с дополнительными соответствиями.Это приведет к другой ошибке:

ошибка: использование 'FoobarProtocol' в качестве конкретного типа, соответствующего протоколу 'Equatable', не поддерживается

Это потому, что Equatable соответствие - это просто соответствие другому протоколу.Реализация по умолчанию static func == (lhs:rhs:) может создать впечатление, что это полная реализация, но это не так. Это все еще соответствие, пока конкретный тип не адаптируется к этому протоколу. Реализация по умолчанию автоматически пробуждается, когда протокол используется в конкретной реализации.

Короче: Протокол в Swift не может быть равносильным.Только конкретный тип может быть уравновешенным.

Альтернативные варианты

  1. Создание типа бетона без наследования с использованием struct .
  2. Используйте наследование с классами вместо структур, чтобы вы могли иметь несколько конкретных реализаций
  3. Создать объект-оболочку , который имеетсвойство с типом протокола
...