Swift5:如何在声明变量时指定符合协议的泛型类型

Swift 5: how to specify a generic type conforming to protocol when declaring a variable

我在 Swift 5. 我有协议:

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

我想在代码中的某处引用此协议的一个实例。也就是说,我想要 foo : 或实现 Pipe 的通用类型 T 的变量。根据此文档:https://docs.swift.org/swift-book/ReferenceManual/GenericParametersAndArguments.html

我试过写:

var imageSource: <Pipe T>

以及所述符号的任何排列,即 imageSource: 但所有情况下的语法都是错误的。

其实T符合两个协议,Renderable和Pipe,所以我很想:

var imageSource: <Pipe, Renderable T>

从语法上讲这是乱码,但从语义上讲这并不是一个罕见的用例。

__________________ 在给出两个答案后编辑 __________

我尝试为此 post 简化 Pipe 协议,但现在我意识到我简化了太多。在我的代码库中它是

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

这就是为什么那里有一个 T。但这并不重要,如果我能够在上面写下我想要的,我可以删除batch() -> [T]

这称为广义存在主义,在 Swift 中不可用。具有关联类型的协议描述其他类型;它本身不是类型,不能是变量的类型,也不能放入集合中。

此特定协议没有多大意义,因为您不会在任何地方使用 T。但是您需要做的是将其拉入包含类型:

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

不过,我怀疑您真的想以不同的方式重新设计它。这看起来像是一种相当常见的协议滥用。您可能希望 PipeRenderer 类型是结构(甚至只是函数)。在不知道调用代码是什么样子的情况下,我不能准确地说出你将如何设计它。

如果您删除 T(此处未使用),Max 的回答将解决此问题。没有关联类型的协议具有隐式存在类型,因此您可以将它们视为 "normal" 类型(将它们分配给变量或将它们放入集合中)。

当您希望您的协议适用于多种类型时,可以使用关联类型,想想一个 Container 协议可能有多个方法都处理一个包含的类型。

但是你的协议不是那个,它不需要知道任何其他类型来指定必要的行为,所以去掉关联的类型。

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

class Foo {
  var imageSource: Pipe & Renderable
}