【问题标题】:Why a protocol with typealias is not sufficient for the associated type requirements?为什么带有 typealias 的协议不足以满足相关的类型要求?
【发布时间】:2017-11-29 13:56:28
【问题描述】:

我知道在我的协议中使用typealiaslimitations。它阻止我做类似的事情:

protocol Provider {
    associatedtype R

    func receiveString(s: R)
}

struct ProviderManager {

    let providers: [(Provider)]
}

因为ProviderManager不知道R的类型,所以报错:

Protocol 'Provider' 只能用作通用约束,因为它具有 Self 或关联的类型要求

但是,为什么我不能引入指定关联类型的中间协议?比如:

protocol Provider {
    associatedtype R

    func receiveString(s: R)
}

protocol StringProvider: Provider {
    typealias R = String
}

struct ProviderManager {
    let providers: [(StringProvider)]
}

即使实现StringProvider 协议按预期工作,上述方法仍然不起作用:

final class MyStringProvider: StringProvider  {
    func receiveString(s: String) {
        //do something
    }
}

MyStringProvider 的上述实现有效。但我仍然不能在数组中使用StringProvider。为什么不呢?

【问题讨论】:

  • 在swift 4中,定义protocol StringProvider: Provider where R == String { }
  • 当然可以,但是我要问的问题还是一样。
  • 查看this question 及其答案

标签: swift generics


【解决方案1】:

您不能创建“协议”类型的变量/属性。您可以创建符合您的协议的某种类型的变量/属性(在您的情况下为数组)。试试这个:

protocol StringProvider : Provider where R == String {
}
struct StringProviderStruct : StringProvider {
    func receiveString(s: String) {
    }
}
struct ProviderManager {
    let providers: [StringProviderStruct]
}

【讨论】:

  • 是的,但是我不能像在 Java 中使用抽象类那样为StringProviderStruct 的子级提供“协议”。我更喜欢“AnyCollection”类型擦除包装解决方案。
  • 再次重申:您不能实例化协议。您可以实例化符合协议的结构或类。这根本行不通:let providers: [(protocol-not-class-or-struct)]
  • 很抱歉没有正确传达我的意图。我明白我们不能做我在我的问题中尝试的事情。我的评论试图传达这一点,因为我们不能,“AnyCollection”类型擦除的包装器解决方案更适合我的用例而不是你的用例。
【解决方案2】:

Protocol 'Provider' 只能用作通用约束,因为它具有 Self 或关联的类型要求

要消除此错误,您必须以这种方式创建结构:

struct ProviderManager<P: Provider> {
    var providers: [P]
}

编辑:

你可以像这样实例化你的经理:

let manager: ProviderManager = ProviderManager(providers: [MyStringProvider()])

【讨论】:

  • 谢谢,但这似乎不起作用。如果我尝试:let manager: ProviderManager&lt;StringProvider&gt;,我会得到“不支持将 'StringProvider' 用作符合协议 'StringProvider' 的具体类型”。我需要传递StringProvider 的特定类实现之一,这违背了传递P: StringProvider 类型的意义。
  • @ADev 我已经编辑了我的答案,希望它对您的需要有所帮助。
  • 谢谢!除了我不想只传递MyStringProvider 的实例之外,这几乎是我想要的方式。相反,我想要StringProvider 协议的实例。假设我有MyStringProviderMyOtherStringProvider。用你的解决方案我做不到let manager: ProviderManager = ProviderManager(providers: [MyStringProvider(), MyOtherStringProvider()])
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-22
  • 1970-01-01
  • 2019-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多