Ответ 1
Сначала рассмотрим определение оператора ===
. Это не просто проверка равенства между значением двух экземпляров, но он проверяет, указывают ли две переменные на один и тот же экземпляр объекта (см. "Операторы идентификации" здесь).
Итак, ваш примерный код не совсем прав:
var a1 = A()
var a2 = A()
var a3 = a2
a1 === a2 // actually false, a1 and a2 were instantiated separately
a2 === a3 // true, because they are the same instance
Таким образом можно сравнивать только классы, потому что все, что не является классом в Swift, имеет значение-значение *, а две переменные с переменной величиной не могут указывать на один и тот же экземпляр.
Поэтому, если вы попытаетесь сравнить обычный протокол с ===
, у Swift недостаточно информации для использования оператора. Экземпляры, которые вы сравниваете (p1
и p2
), могут быть экземплярами классов, или они могут быть экземплярами структуры, а во время компиляции Swift не может сказать, хорошо ли это.
Если вы хотите использовать протокол как тип таким образом и сравнить с ===
, вам нужно объявить только протокол класса, используя class
в качестве первого элемента в наследовании протокола список, например:
protocol P : class {
}
class A : P {
}
Теперь вы можете делать то, что пытались, без ошибки компилятора:
var p1:P = a1
var p2:P = a2
var p3:P = a3
p1 === p2 // false
p2 === p3 // true
* Семантически, во всяком случае. Swift делает много заглавных ссылок, но навязывает это поведение, основанное на значении, поэтому для целей этого обсуждения просто переходите к struct
и enum
, которые действительно вводятся по значению.