【问题标题】:How can I pass protocol types to generic functions?如何将协议类型传递给泛型函数?
【发布时间】:2017-07-19 11:29:31
【问题描述】:

我想根据类型(URL 的一部分,如果你必须知道的话)创建字符串。

考虑这个示例代码:

import Foundation


protocol TestP {
    var p: Int { get }
}
protocol TestQ: TestP {
    var q: Int { get }
}
struct TestR: TestQ {
    var p = 1
    var q = 2
}

func toDescription<T: TestP>(type: T.Type) -> String {
    switch type {
        case is TestR.Type: return "Arrrr"
        default: return "unsupported"
    }
}

这看起来相当不错;我不需要依赖不安全的措施(字符串),也不需要单独的枚举。

我们来看一些用法示例:

func example1<T: TestP>(val: T) {
    print("Processing \(toDescription(type: T.self))")
}

func example2() {
    print("Processing \(toDescription(type: TestR.self))")
}

func example3() {
    print("Processing \(toDescription(type: TestQ.self))")
}

虽然前两个函数很好(通用版本特别好!),但第三个不能编译:

错误:在参数类型TestQ.Protocol.TypeTestQ.Protocol 不符合预期类型TestP

TestP.TypeTestP.Protocol 也不能用作参数。

如何将协议类型传递给(通用)函数?

【问题讨论】:

  • 这没有充分的理由编译 - 比如说 TestP 有一个 static 要求。您可以在toDescription 中调用type 上的该要求——但如果您能够传入TestQ.self,则没有可调用的实现。
  • 这是更大限制的一部分(为了防止这些不安全的情况,但在其他情况下充满了完全安全的边缘情况),即protocols don't conform to themselves - 所以你不能使用TestQ 作为符合 TestP 的类型。
  • @Hamish 我明白了。我想我希望那时能够写func f&lt;T: TestP&gt;(type: T.Protocol),在这种情况下,编译器可以检查我没有在协议类型上调用静态成员。 (好吧,即使在我编写的版本中,它也可能会阻止我访问静态成员,因为它可能会失败。)
  • 有趣的事实:如果您切换此类参数type,模式is TestQ.Type 不会引发警告“从不匹配”。
  • 如果协议确实符合自己,那么是的,我希望像 func f&lt;T: TestP&gt;(type: T.Protocol) 这样的东西可以工作(尽管它会禁止你的前两个示例工作)

标签: swift generics swift-protocols type-bounds


【解决方案1】:
protocol TestP {
    var p: Int { get }
}
protocol TestQ: TestP {
    var q: Int { get }
}
struct TestR: TestQ {
    var p = 1
    var q = 2
}

struct TestS: TestP
{
    var p = 42
}

func toDescription<T: TestP>(type: T.Type) -> String
{
    switch type
    {
    case let x where x == TestR.self:
        return "Arrr"
    default:
        return "Unsupported"
    }
}

print (toDescription(type: TestR.self)) // Arrr
print (toDescription(type: TestS.self)) // Unsupported

【讨论】:

  • 这并不能解决 OP 遇到的问题。 OP 正在尝试将 TestQ.self 传递给 toDescription(type:),但它会产生编译器错误。
  • 此外,由于缺乏解释,纯代码的答案很少能提供很多洞察力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 2019-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多