我在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>
在语法上这是胡言乱语,但从语义上讲,这不是一个罕见的用例。
____在给出两个答案后编辑__________
我曾尝试简化本文的Pipe
协议,但现在我意识到我简化了太多。在我的代码库中,它是
protocol Pipe {
associatedtype T
func await() -> Void
func yield( to: Any, with listener: Selector ) -> Void
func batch() -> [T]
}
这就是为什么那里有T的原因。但这不是至关重要的,如果我能够在上面编写所需的内容,则可以删除batch() -> [T]
。
当您希望您的协议可以用于多种类型时,请使用关联类型,以为Container
协议可能具有多种方法来处理一个包含的类型。
但是您的协议不是那样,它不需要知道任何其他类型来指定必要的行为,因此请摆脱关联的类型。
protocol Pipe {
func await() -> Void
func yield( to: Any, with listener: Selector ) -> Void
}
class Foo {
var imageSource: Pipe & Renderable
}
这称为广义存在性,在Swift中不可用。具有关联类型的协议描述了其他类型。它本身不是类型,也不能是变量的类型,也不能放入集合中。
由于您不在任何地方使用T
,因此该特定协议没有多大意义。但是您需要做的就是将其拉入包含类型:
struct Something<Source> where Source: Pipe & Renderable {
var imageSource: Source
}
但是,我怀疑您真的想以其他方式重新设计。这看起来像是对协议的普遍滥用。您可能希望Pipe
和Renderer
类型是结构(甚至只是函数)。在不知道调用代码是什么样的情况下,我无法确切地说出您将如何设计它。
如果删除T
(此处未使用),则Max的答案将解决此问题。没有关联类型的协议具有隐式的存在性类型,因此您可以将它们某种程度上视为“正常”类型(将它们分配给变量或放入集合中)。