2016-11-21 74 views
2

我想提高我对泛型的知识,并且遇到了一个我无法解决的问题。我有两种不同的类型(IntDouble)。这两种类型都实现了功能advanced(by:)。我想制作一个通用函数来调用给定类型的advanced(by:)实现通用接口的类型的通用函数

好处是我可以用替代intAdvancedByTen(value:)doubleAdvancedByTen(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:)方法?

回答

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 
+0

伟大的作品,我真的很高兴。谢谢! :)我很困惑,因为这是我第一次看到使用大写'Self',所以这里有一个链接来解释'self'和'Self'之间的区别:http://stackoverflow.com/questions/27863810/distinction -in-SWIFT之间大写自和小写自 – Andrej

1

不需要定义自己的协议 - advanced(by:)由标准libary的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