Swift 5: как указать общий c тип, соответствующий протоколу, при объявлении переменной - PullRequest
0 голосов
/ 27 мая 2020

Я использую Swift 5. У меня есть протокол:

protocol Pipe {
    associatedtype T
    func await() -> Void
    func yield( to: Any, with listener: Selector ) -> Void
}

И я хотел бы сослаться на экземпляр этого протокола где-нибудь в коде. То есть я хочу foo: или переменную generi c типа T, реализующую Pipe. В этой документации: https://docs.swift.org/swift-book/ReferenceManual/GenericParametersAndArguments.html

Я попытался написать:

var imageSource: <Pipe T>

и любую перестановку указанных символов, ie imageSource: но синтаксис неверен все случаи.

Фактически, T соответствует двум протоколам, Renderable и Pipe, поэтому я действительно хочу:

var imageSource: <Pipe, Renderable T>

По синтаксису это gibberi sh, но семантически это не необычный вариант использования.

__________________ EDIT после того, как были даны два ответа __________

Я попытался упростить протокол Pipe для этого сообщения, но теперь понимаю, что слишком упростил его. В моей кодовой базе это

  protocol Pipe {
        associatedtype T
        func await() -> Void
        func yield( to: Any, with listener: Selector ) -> Void
        func batch() -> [T]
    }

Вот почему там стоит буква T. Но это не критично, я могу сбросить batch() -> [T], если смогу написать то, что хочу выше.

Ответы [ 2 ]

2 голосов
/ 27 мая 2020

Связанный тип используется, когда вы хотите, чтобы ваш протокол работал с множеством типов, подумайте о протоколе Container, который может иметь несколько методов, работающих с одним содержащимся типом.

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

protocol Pipe {
    func await() -> Void
    func yield( to: Any, with listener: Selector ) -> Void
}

class Foo {
  var imageSource: Pipe & Renderable
}
2 голосов
/ 27 мая 2020

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

Этот протокол c не имеет большого смысла, поскольку вы не используете T везде. Но что вам нужно сделать, так это вставить это в содержащий тип:

struct Something<Source> where Source: Pipe & Renderable {
    var imageSource: Source
}

Однако я подозреваю, что вы действительно хотите переделать это по-другому. Это похоже на довольно частое злоупотребление протоколами. Вероятно, вам нужны типы Pipe и Renderer, которые являются структурами (или даже просто функциями). Не зная, как выглядит вызывающий код, я не могу точно сказать, как вы его спроектируете.

Если вы удалите T (который здесь не используется), то ответ Макса решит эту проблему. . Протоколы без связанных типов имеют неявный экзистенциальный тип, и поэтому вы можете относиться к ним как к «нормальным» типам (присваивая их переменным или помещая их в коллекции).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...