Swift中的多类型约束

Log*_*gan 119 swift

假设我有这些协议:

protocol SomeProtocol {

}

protocol SomeOtherProtocol {

}
Run Code Online (Sandbox Code Playgroud)

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

func someFunc<T: SomeProtocol>(arg: T) {
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)

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

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

}
Run Code Online (Sandbox Code Playgroud)

类似的东西使用逗号,但在这种情况下,它会启动一个不同类型的声明.这是我尝试过的.

<T: SomeProtocol | SomeOtherProtocol>
<T: SomeProtocol , SomeOtherProtocol>
<T: SomeProtocol : SomeOtherProtocol>
Run Code Online (Sandbox Code Playgroud)

Jia*_*aro 222

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

斯威夫特2:

func someFunc<T where T:SomeProtocol, T:SomeOtherProtocol>(arg: T) {
    // stuff
}
Run Code Online (Sandbox Code Playgroud)

Swift 3&4:

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    // stuff
}
Run Code Online (Sandbox Code Playgroud)

或更强大的where子句:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol{
    // stuff
}
Run Code Online (Sandbox Code Playgroud)

您当然可以使用协议组合(例如protocol<SomeProtocol, SomeOtherProtocol>),但它的灵活性稍差.

使用where允许您处理涉及多种类型的情况.

您可能仍希望在多个位置组合协议以便重用,或者只是为组合协议提供有意义的名称.

  • 有什么办法可以对类型约束中的类和结构做同样的事情?例如`&lt;T其中T:SomeStruct,T:AnotherStruct&gt;`?对于类,编译器似乎将其解释为说“ T是两者的子类”,而对于结构,它只是抱怨“类型T约束为非协议类型”。 (2认同)
  • 有没有办法告诉T必须是某种对象类型并实现某种协议? (2认同)

Jea*_*let 73

你有两种可能性:

  1. 你使用了Jiaaro答案中指出的where子句:

    func someFunc<T where T : SomeProtocol, T : SomeOtherProtocol>(arg: T) {
        // do stuff
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您使用协议组合类型:

    func someFunc<T : protocol<SomeProtocol, SomeOtherProtocol>>(arg: T) {
        // do stuff
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • imo第二个解决方案更漂亮,我会回答这个问题,它也更完整地呈现两个选项 (2认同)
  • 在声明一个`typealias`时,2号是唯一一个适用于我的Swift 2.谢谢! (2认同)

nck*_*cke 19

Swift 3.0的发展带来了一些变化.我们的两个选择现在看起来有点不同.

where在Swift 3.0中使用一个子句:

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

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

}
Run Code Online (Sandbox Code Playgroud)

protocol<>在Swift 3.0中使用构造:

使用该protocol<>构造的组合已被弃用.现在越早protocol<SomeProtocol, SomeOtherProtocol>看起来像这样:

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

}
Run Code Online (Sandbox Code Playgroud)

引用.

有关更改的更多信息,请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


Ima*_*tit 12

Swift 3提供多达3种不同的方式来声明您的功能.

protocol SomeProtocol {
    /* ... */
}

protocol SomeOtherProtocol {
    /* ... */        
}
Run Code Online (Sandbox Code Playgroud)

1.使用&操作员

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

2.使用where条款

func someFunc<T>(arg: T) where T: SomeProtocol, T: SomeOtherProtocol {
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

3.使用where子句和&运算符

func someFunc<T>(arg: T) where T: SomeProtocol & SomeOtherProtocol {
    /* ... */        
}
Run Code Online (Sandbox Code Playgroud)

另请注意,您可以使用typealias以缩短功能声明.

typealias RequiredProtocols = SomeProtocol & SomeOtherProtocol

func someFunc<T: RequiredProtocols>(arg: T) {
    /* ... */   
}
Run Code Online (Sandbox Code Playgroud)