Расширение Swift Array с предложением where не работает с подпротоколами

Я написал код, который, по моему мнению, должен работать в Swift 2 (Xcode 7b4), но он не компилируется. Я надеюсь получить некоторые мысли о том, должно ли то, что я пытаюсь сделать, быть действительным.

Рассмотрим этот пример расширения Array:

extension Array where Element: AnyObject {
    mutating func appendUniqueInstance(e: Element) {
        for element in self {
            if (element === e) {
                return
            }
        }

        self.append(e)
    }
}

Во-первых, что я имею в виду под массивом, элементами которого являются AnyObject? По сути, я говорю, что массив должен содержать разнородную группу объектов, не относящихся к типу значения, которые можно сравнивать на предмет равенства экземпляров (===).

Пример функции appendUniqueInstance() вставляет элемент в массив только в том случае, если его еще нет в массиве. Это похоже на операцию Set insert(), но, очевидно, обеспечивает упорядочение и (что более важно) не налагает требования однородного типа Set (через Equatable использование Self).

Если я сейчас определяю протокол P и класс C, который реализует P:

protocol P : AnyObject {}

class C : P {}

и создайте экземпляр C:

let c = C()

Тогда эти очень очевидные вещи верны:

let cIsAnyObject = c as AnyObject   // ok
let cIsP = c as P                   // ok

И теперь я могу сделать следующее:

var a1 = [AnyObject]()              // []

a1.appendUniqueInstance(c)          // [c]
a1.appendUniqueInstance(c)          // [c]

Пока все хорошо, а теперь о проблемном случае:

var a2 = [P]()

a2.append(c)                        // ok, -> [c]

// Compiler error: Cannot invoke 'appendUniqueInstance' with an argument list of type '(C)'
a2.appendUniqueInstance(c)

Здесь a2 вводится как массив P, поэтому должно быть вполне допустимо сделать с append экземпляр P, и действительно строка a2.append(c) работает так, как мы и ожидали.

Однако вызов функции расширения Array appendUniqueInstance() вызывает ошибку компилятора.

Насколько я могу судить, компилятор, кажется, запутался в том, что может быть передано в appendUniqueInstance(), и не понимает (или допускает по какой-то причине), что C (через P) является AnyObject.

Кстати, если я объявлю P вместо этого как:

@objc protocol P : AnyObject {}

тогда все компилируется просто отлично, но я также должен убедиться, что все в протоколе P соответствует @objc, а это не то, что я хочу.

Итак, после всего этого у меня вопрос: похоже ли это на то, что должно работать? Я надеюсь, что это не просто случай неправильного синтаксиса объявления, но, думаю, я буду рад, если это так.


person par    schedule 29.07.2015    source источник


Ответы (2)


Если вы щелкнете по команде AnyObject, вы заметите, что это протокол, соответствующий @objc. Поэтому я предполагаю, что это причина, по которой он просит использовать @objc. Я заметил, что если мы делаем C подклассом NSObject, вам не нужно явно делать реализацию методов из P для соответствия @objc

@objc protocol P : AnyObject {
    func hey()
}

class C : NSObject, P {
    func hey() {
        print("hey")
    }
}
person Sumeet    schedule 09.02.2016

Похоже, что ошибка, о которой сообщил компилятор в то время, когда я написал исходный вопрос, просто вводила в заблуждение, а функциональность, которую я пытался получить, не поддерживалась (и до сих пор не поддерживается) Swift.

С Xcode 8.2.1 и Swift 3 сообщается более точная ошибка:

// error: using 'P' as a concrete type conforming
//   to protocol 'AnyObject' is not supported
a2.appendUniqueInstance(c)
person par    schedule 26.02.2017