Следующий код скомпилирован без проблем
protocol Animal {
}
var animals = [Animal]()
Однако у нас есть новое требование, где нам нужно сравнить массив Animal
protocol Animal {
}
func x(a0: [Animal], a1: [Animal]) -> Bool {
return a0 == a1
}
var animals = [Animal]()
Приведенный выше код приведет к ошибке компиляции
протокол «Животное» как тип не может соответствовать «Приравненному»
Мы склонны исправлять
protocol Animal: Equatable {
}
func x(a0: [Animal], a1: [Animal]) -> Bool {
return a0 == a1
}
var animals = [Animal]()
В строке объявления массива мы получаем ошибку
протокол «Животное» может использоваться только в качестве общего ограничения, поскольку он имеет требования к типу Self или связанному с ним типу.
Могу я знать,
- Почему у нас может быть массив протоколов до того, как протокол будет соответствовать Equatable?
- Почему нам не разрешено иметь массив протоколов, если протокол соответствует Equatable?
- Какие есть хорошие способы исправить такую ошибку?
3 ответа
Спасибо @Alexander и его указанному видеоресурсу - https://youtu.be/_m6DxTEisR8?t=2585< /а>
Вот хороший обходной путь для преодоления текущего ограничения протокола Swift.
protocol Animal {
func isEqual(to: Animal) -> Bool
}
func isEqual(lhs: [Animal], rhs: [Animal]) -> Bool {
let count0 = lhs.count
let count1 = rhs.count
if count0 != count1 {
return false
}
for i in 0..<count0 {
if !(lhs[i].isEqual(to: rhs[i])) {
return false
}
}
return true
}
// struct. By conforming Equatable, struct is getting an auto
// implementation of "static func == (lhs: Dog, rhs: Dog) -> Bool"
struct Dog: Animal, Equatable {
func isEqual(to other: Animal) -> Bool {
guard let other = other as? Dog else { return false }
return self == other
}
}
// class
class Cat: Animal, Equatable {
static func == (lhs: Cat, rhs: Cat) -> Bool {
// TODO:
return true
}
func isEqual(to other: Animal) -> Bool {
guard let other = other as? Cat else { return false }
return self == other
}
}
var animals0 = [Animal]()
var animals1 = [Animal]()
// Instead of using
// if animals0 == animals1 {
// we will use the following function call
if isEqual(lhs: animals0, rhs: animals1) {
}
Эта часть Swift может немного сбивать с толку, и есть планирует его улучшить.
Когда вы пишете что-то вроде a0: [Animal]
, вы говорите, что ваша функция принимает аргумент массива, элементы которого являются экзистенциалами протокола (протокола Animal
).
Экзистенциальный Animal
— это объект, предоставляющий своему пользователю унифицированный доступ ко всем требованиям (свойствам, методам, индексам, инициализаторам и т. д.) протокола Animal
, независимо от конкретного типа базового объект (Cat
, Dog
и т. д.).
В посте нового мира SE-0335 ваш код должен быть написан так:
func x(a0: [any Animal], a1: [any Animal]) -> Bool {
return a0 == a1
}
Проблема становится более ясной: нет никакой гарантии, что a0
и a1
содержат животных одного и того же типа. Теперь это буквально прописано в коде: это массивы любого типа животных. Каждый из них может содержать животных любого типа, и нет никакой связи между типами животных в a0
и в a1
. Это проблема, потому что Equatable
специфичен для проверки своих требований: его оператор ==
применим только к двум объектам одного типа.
Чтобы исправить это, вам нужно сделать вашу функцию универсальной, чтобы содержать a0
и a1
объекты определенного типа:
func x<A: Animal>(a0: [A], a1: [A]) -> Bool {
return a0 == a1
}
a1: [A]
Протокол не может соответствовать Equatable. Причина в том, что для этого требуется Я. Self относится к конкретному типу (например, struct/class), который соответствует Equatable. Если вы хотите иметь возможность использовать протокол вместо конкретного типа для массива, вам нужно написать функцию сжатия самостоятельно:
protocol Animal {
var name: String { get }
}
func compare(lhsAnimals: [Animal], rhsAnimals: [Animal]) -> Bool {
guard lhsAnimals.count == rhsAnimals.count else { return false}
for i in 0..<lhsAnimals.count {
if lhsAnimals[i].name != rhsAnimals[i].name {
return false
}
}
return true
}
let animals: [Animal] = [Dog(name: "Albert"), Dog(name: "Kiki"), Dog(name: "Caesar")]
Похожие вопросы
Связанные вопросы
Новые вопросы
ios
iOS - мобильная операционная система, работающая на Apple iPhone, iPod touch и iPad. Используйте этот тег [ios] для вопросов, связанных с программированием на платформе iOS. Используйте связанные теги [target-c] и [swift] для проблем, характерных для этих языков программирования.
Cat : Animal
иDog: Animal
. Как вы сравниваете типы?