实现公共接口

时间:2016-11-21 21:20:28

标签: swift generics

我想增加我对仿制药的了解,我遇到了一个无法解决的问题。我有两种不同的类型(IntDouble)。两种类型都实现了函数advanced(by:)。我想创建一个泛型函数来调用给定类型的advanced(by:)

这样做的好处是我可以用intAdvancedByTen(value:)替换doubleAdvancedByTen(value:)genericAdvancedByTen(value:)

这是我的游乐场:

let myDouble: Double = 1
let myInt: Int = 2

func intAdvanceByTen(value: Int) {     // Replace this function
    value.advanced(by: 10)
}

func doubleAdvanceByTen(value: Int) {  // ...and this function
    value.advanced(by: 10)
}

protocol CanAdvance {
    func advance(_ by: Any)
}
                                       // ...with this generic function
func genericAdvanceByTen(value: CanAdvance) {
    value.advance(10)
}

genericAdvanceByTen(value: myInt)      // Error: Argument "Int" does not conform to expected type "CanAdvance"

如何让泛型函数知道传递的类型实现了advanced(by:)方法?

2 个答案:

答案 0 :(得分:1)

试试这个:

protocol CanAdvance {
    // This method is intentionally designed to have the same signature as the
    // methods built into Int and Double
    func advanced(by: Self) -> Self

    // We need this primarily for the definition of the constant 10. The built
    // in `advanced` function requires the distance to be of the same type.
    //
    // The conversion syntax in Swift is via init:
    //      let aDouble = Double(anInt)
    // Not the C-like cast:
    //      let aDouble = anInt as! Double    // invalid
    //
    // Hence we must have a way to convert 10 to the appropriate Int or Double.
    // Conveniently, both types can convert from an Int32 so we  put this
    // requirement in the protocol
    init(_ value: Int32)
}

extension Int : CanAdvance { }
extension Double : CanAdvance { }

func genericAdvanceByTen<T: CanAdvance>(value: T) -> T {
    let distance = T(10)
    return value.advanced(by: distance)
}

genericAdvanceByTen(value: 2)       // 12
genericAdvanceByTen(value: 3.14)    // 13.14

答案 1 :(得分:1)

无需定义自己的协议 - advanced(by:)由标准的libary&#39; Strideable协议定义:

public protocol Strideable : Comparable {

    /// A type that can represent the distance between two values of `Self`.
    associatedtype Stride : SignedNumber

    // ...

    /// Returns a `Self` `x` such that `self.distance(to: x)` approximates `n`.
    ///
    /// If `Stride` conforms to `Integer`, then `self.distance(to: x) == n`.
    ///
    /// - Complexity: O(1).
    public func advanced(by n: Self.Stride) -> Self
}

因此,您只想约束函数以获取Strideable输入。

鉴于Stride关联类型(advanced(by:)期望作为参数)被约束为SignedNumber,它必须符合ExpressibleByIntegerLiteral - 这允许我们通过整数字面直接到它。

例如:

func genericAdvancedByTen<T : Strideable>(value: T) -> T {
    // Utilise the fact that T.Stride is ExpressibleByIntegerLiteral.
    return value.advanced(by: 10)
}

print(genericAdvancedByTen(value: 2))       // 12
print(genericAdvancedByTen(value: 3.14))    // 13.14