Подтвердить что ты не робот

Протокол не поддерживает оператор "==="?

Кажется, что protocol не поддерживает оператор ===, а class делает.

protocol P {
}

class A : P {
}

var a1 = A()
var a2 = A()
var p1:P = a1
var p2:P = a2

a1 === a2    // true
p1 === p2    // error: Type 'P' does not conform to protocol 'AnyObject'

Я думаю, что это может быть связано с тем, что конкретный тип, соответствующий протоколу, также может быть типом значения (например, struct), который не поддерживает оператор ===. Мне просто интересно, что если я уверен, что настоящий тип является классом, как я могу сравнить ссылки на них, например, p1 и p2 здесь?

4b9b3361

Ответ 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, которые действительно вводятся по значению.

Ответ 2

Равенство между протоколами

Снимите это на детской площадке и на своем пути.

protocol IPositional:class{}
class A:IPositional{}
class B:IPositional{}
let a:IPositional = A()
let b:IPositional = B()
let c:IPositional = a
a === b //false
a === c //true

Ответ 3

Согласуйте протокол с class или AnyObject Это означает, что только классы смогут соответствовать этому протоколу, а не struct.

Например, из:

protocol P {
}

to (версия Swift 4)

protocol P : AnyObject {
}

или (версия Swift 3)

protocol P : class {
}