Кажется, что дженерики Swift работают нормально, пока я не пытаюсь их комбинировать любым практическим способом.Я использую Swift 4.1, и я хотел бы создать универсальный массив, содержащий только слабые ссылки.Я могу определить это как WeakList<T>
.Пока все хорошо.Но: я бы хотел использовать протокол для T
.Свифт говорит, что нет ..
import Foundation
protocol Observer: class {
func stateChanged(sender: SomeClass, newState: Int)
}
struct WeakList<T> where T: AnyObject {
struct Ptr {
weak var p: T?
}
private var storage: [Ptr] = []
var aliveObjects: [T] {
var result: [T] = []
for ptr in storage {
if let p = ptr.p {
result.append(p)
}
}
return result
}
mutating func add(_ obj: T) {
storage.append(Ptr(p: obj))
}
// Let's ignore for a moment that this implementation leaks memory badly.
}
class SomeClass {
var someVar: WeakList<Observer> = WeakList<Observer>()
// Error: WeakList requires that 'Observer' be a class type
var thisIsOk: WeakList<NSObject> = WeakList<NSObject>()
}
(это не мой оригинальный код, а минимальный проверяемый пример, который содержит достаточно деталей, чтобы никто не мог сказать «просто удалите ограничение AnyObject из структуры»)
Полагаю, то, что я пытаюсь сделать, просто невозможно.Либо это?Просто разочаровывает, что 4 раза из 5, когда я пытаюсь что-то сделать с помощью дженериков Swift, я позже узнаю, что то, что я пытаюсь сделать, просто невозможно.(Кстати, я могу легко реализовать то же самое в Objective-C.)
- Я пытался изменить ограничение
class
на ограничение AnyObject
=>, тоже не работает.
- Я пытался изменить ограничение
AnyObject
на class
ограничение => даже не компилируется.
- А изменение на
protocol Observer where Self: NSObject
неизменить что-нибудь.NSObject
- это тип класса, Observer
- это NSObject
.Из этого следует, что Observer
является типом класса.Отношения «есть» здесь не кажутся транзитивными.