一次扩展多个协议

时间:2021-03-19 03:16:58

标签: swift

我想为多个协议编写扩展,发现 this posting 非常有趣,但我无法完全遵循 Matthew Seaman。

在这种情况下,我想编写自己的 extension BinaryNumber,并将其添加到 BinaryIntegerBinaryFloatingPoint。但是当我尝试添加我的协议时,Xcode 显示错误消息 Extension of protocol 'BinaryInteger'(或 'BinaryFloatingPoint')不能有继承子句

这是我的代码:

protocol BinaryNumbers {} // my protocol

extension BinaryNumbers {
    func foo() -> Void {
        print("It works!")
    }
}

// try to extend Swift protocols
extension BinaryInteger : BinaryNumbers {} // doesn't work
extension BinaryFloatingPoint : BinaryNumbers {} // doesn't work

//更新

@sweeper 建议扩展 Numeric,所以我尝试了,但出现错误。

extension Numeric {
    func foo() -> Bool {
        return self <= 127
        // Referencing operator function '<=' on 'BinaryInteger' requires
        // that 'Self' conform to 'BinaryInteger'
    }
}

当我一一扩展 BinaryIntegerBinaryFloatingPoint 时,它起作用了。

1 个答案:

答案 0 :(得分:2)

一般来说,不可能在多个协议上编写单个扩展。这将要求编译器找出所有这些协议中所有成员的集合交集(那些是您在扩展中可以访问的成员),而编译器无法做到这一点。

为避免代码重复,您需要确定您需要的成员 - 在您的情况下 init(integerLiteral:)<=,将它们放入您自己的协议中,并使具体< /em> 您希望扩展适用的类型,符合您自己的协议:

// inheriting from Comparable and ExpressibleByIntegerLiteral gives you the members you need
protocol BinaryNumbers : Comparable & ExpressibleByIntegerLiteral {

}

extension BinaryNumbers {
    func atMost127() -> Bool {
        self <= 127
    }
}

extension Int: BinaryNumbers {}
extension Int8: BinaryNumbers {}
extension Int16: BinaryNumbers {}
extension Int32: BinaryNumbers {}
extension Int64: BinaryNumbers {}
// ... plus the unsigned versions, if you need them

extension Float16: BinaryNumbers {}
extension Float32: BinaryNumbers {}
extension Float64: BinaryNumbers {}
extension Float80: BinaryNumbers {}

现在您可能会问,既然它们提供了我们正在使用的所有成员,那么为什么不直接扩展 Comparable & ExpressibleByIntegerLiteral 呢?好吧,因为那不是名义类型,而且你不能在非名义类型上写扩展:(

但是,你可以这样写:

// now you don't need your own "BinaryNumbers"!
extension Comparable where Self: ExpressibleByIntegerLiteral {
    func atMost127() -> Bool {
        self <= 127
    }
}

您之所以能够这样做,是因为您需要的两个成员都来自协议。如果由于某种原因您需要一个 BinaryFloatingPointBinaryInteger 都有的成员,但它们所遵循的任何协议都没有提供,那么您需要为这些成员编写自己的协议,并且手动使所有内容都符合该协议。