【问题标题】:Multiple Type Constraints in SwiftSwift 中的多种类型约束
【发布时间】:2014-06-06 19:17:18
【问题描述】:

假设我有这些协议:

protocol SomeProtocol {

}

protocol SomeOtherProtocol {

}

现在,如果我想要一个采用泛型类型的函数,但该类型必须符合 SomeProtocol,我可以这样做:

func someFunc<T: SomeProtocol>(arg: T) {
    // do stuff
}

但是有没有办法为多个协议添加类型约束?

func bothFunc<T: SomeProtocol | SomeOtherProtocol>(arg: T) {

}

类似的东西使用逗号,但在这种情况下,它会开始声明不同的类型。这是我尝试过的。

<T: SomeProtocol | SomeOtherProtocol>
<T: SomeProtocol , SomeOtherProtocol>
<T: SomeProtocol : SomeOtherProtocol>

【问题讨论】:

  • 这是一个特别相关的问题,因为 Swift 文档在泛型章节中没有提到这一点......

标签: swift


【解决方案1】:

您可以使用where clause,它允许您指定任意数量的要求(必须满足所有要求),用逗号分隔

斯威夫特 2:

func someFunc<T where T:SomeProtocol, T:SomeOtherProtocol>(arg: T) {
    // stuff
}

斯威夫特 3 和 4:

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    // stuff
}

或更强大的where子句:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol{
    // stuff
}

您当然可以使用协议组合(例如,protocol&lt;SomeProtocol, SomeOtherProtocol&gt;),但灵活性稍差。

使用where 可以处理涉及多种类型的情况。

您可能仍想组合协议以便在多个地方重用,或者只是为组合的协议起一个有意义的名称。

斯威夫特 5:

func someFunc(arg: SomeProtocol & SomeOtherProtocol) { 
    // stuff
}

这感觉更自然,因为协议在参数旁边。

【讨论】:

  • 天哪,这不合逻辑,但很高兴知道我只想成为这个垃圾邮件发送者之一,自从我需要它以来,我在一个月内还没有意识到这一点。
  • 有什么方法可以对类型约束表达式中的类和结构做同样的事情?例如&lt;T where T:SomeStruct, T:AnotherStruct&gt;?对于类,编译器似乎将其解释为“T 是两者的子类”,而对于结构,它只是抱怨 "Type 'T' constrained to non-protocol type"
  • 对于 OP:s question 协议组合中的具体示例 should 是更可取的方法:上面的解决方案是有效的,但是恕我直言,不必要地弄乱了函数签名。此外,使用协议组合作为类型约束,仍然可以让您使用 where 子句进行其他类型/其他用途,例如func someFunc&lt;U, T: protocol&lt;SomeProtocol, SomeOtherProtocol&gt; where T.SubType == U&gt;(arg: T, arg2: U) { ... } 用于类型别名 SubType 在例如SomeProtocol.
  • 看起来这在 swift3 中已被弃用,建议使用:func someFunc(arg: T) where T:SomeProtocol, T:SomeOtherProtocol {
  • 有没有办法告诉 swift T 需要是某种对象类型并实现某种协议?
【解决方案2】:

你有两种可能:

  1. 您使用 where clause,如 Jiaaro 的回答所示:

    func someFunc<T where T : SomeProtocol, T : SomeOtherProtocol>(arg: T) {
        // do stuff
    }
    
  2. 您使用 protocol composition type

    func someFunc<T : protocol<SomeProtocol, SomeOtherProtocol>>(arg: T) {
        // do stuff
    }
    

【讨论】:

  • imo第二个解决方案更漂亮,我会去这个答案它也更完整地呈现两个选项
  • 在声明 typealias 时,在 Swift 2 下,编号 2 是唯一对我有用的。谢谢!
【解决方案3】:

向 Swift 3.0 的演进带来了一些变化。我们的两个选择现在看起来有些不同了。

在 Swift 3.0 中使用 where 子句:

where 子句现已移至函数签名的末尾以提高可读性。所以多协议继承现在看起来像这样:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol {

}

在 Swift 3.0 中使用 protocol&lt;&gt; 构造:

使用protocol&lt;&gt; 构造的组合已被弃用。之前的 protocol&lt;SomeProtocol, SomeOtherProtocol&gt; 现在看起来像这样:

func someFunc<T:SomeProtocol & SomeOtherProtocol>(arg: T) {

}

参考资料。

有关where 更改的更多信息在这里:https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

而且,关于协议 结构的更多变化在这里:https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md

【讨论】:

    【解决方案4】:

    Swift 3 提供多达 3 种不同的方式来声明您的函数。

    protocol SomeProtocol {
        /* ... */
    }
    
    protocol SomeOtherProtocol {
        /* ... */        
    }
    

    1。使用&amp; 运算符

    func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
        /* ... */
    }
    

    2。使用where 子句

    func someFunc<T>(arg: T) where T: SomeProtocol, T: SomeOtherProtocol {
        /* ... */
    }
    

    3。使用where 子句和&amp; 运算符

    func someFunc<T>(arg: T) where T: SomeProtocol & SomeOtherProtocol {
        /* ... */        
    }
    

    还请注意,您可以使用typealias 来缩短您的函数声明。

    typealias RequiredProtocols = SomeProtocol & SomeOtherProtocol
    
    func someFunc<T: RequiredProtocols>(arg: T) {
        /* ... */   
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多