Swift универсальный тип ссылки

У меня есть проблемы, пытающиеся ограничить общие требования к типу только ссылочными типами. Вот пример кода:

class WeakHolder<Element: AnyObject> {
    weak var element: Element?

    init(element: Element) {
        self.element = element
    }
}

protocol Animal: class { }

class Dog: Animal { }

let dog: Animal = Dog()
let holder = WeakHolder<Animal>(element: dog) // Error: Using "Animal" as a concrete type conforming to protocol 'AnyObject' is not supported.

Если я изменю общее требование на <Element: class>Я получаю ошибку class constraint can only appear on protocol declarations,

Это ограничение дженериков? Маркировки протокола как класса достаточно, чтобы иметь слабую ссылку на этот протокол, нет ли эквивалента в дженериках?

2 ответа

Решение

Ответ прост: у вас не может быть универсального типа, который является протоколом.

Написание синтаксиса проясняет, как это работает: class/struct GenericType<TypeName: TypeConstraints> {}

let thing = GenericType<Type>() where Type is a class or struct that adheres to any constraints

Протокол, требующий принятия типов в качестве класса, означает, что любые приемники являются классами, но сам протокол все еще не является типом.

Возможно, дженерики могут в какой-то момент поддерживать протоколы, но для этого потребуется изменить общий подход к протоколам или дженерикам. Хотя ваш конкретный пример может быть возможен с меньшим объемом закулисной работы, возможно, это может быть реализовано в какой-то момент.

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

Другое решение, которое сработало в моем конкретном случае, заключается в следующем:

class WeakHolder<Element: AnyObject> {
    weak var element: Element?

    init(element: Element) {
        self.element = element
    }
}

protocol Animal: class { }

class Dog: Animal { }

let dog: Animal = Dog()
let holder = WeakHolder<AnyObject>(element: dog as AnyObject)

При доступе к элементу мне просто нужно выполнить возврат к своему протоколу. Конечно, я потеряю безопасность времени компиляции при использовании этого класса с типами значений, но это не проблема в моей ситуации.

Другие вопросы по тегам