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

问题描述 投票:0回答:2

我在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]

swift generics protocols generic-programming
2个回答
2
投票

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

但是您的协议不是那样,它不需要知道任何其他类型来指定必要的行为,因此请摆脱关联的类型。

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

class Foo {
  var imageSource: Pipe & Renderable
}

1
投票

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

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

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

但是,我怀疑您真的想以其他方式重新设计。这看起来像是对协议的普遍滥用。您可能希望PipeRenderer类型是结构(甚至只是函数)。在不知道调用代码是什么样的情况下,我无法确切地说出您将如何设计它。

如果删除T(此处未使用),则Max的答案将解决此问题。没有关联类型的协议具有隐式的存在性类型,因此您可以将它们某种程度上视为“正常”类型(将它们分配给变量或放入集合中)。

© www.soinside.com 2019 - 2024. All rights reserved.