Extension of constructed generic type in Swift

前端 未结 7 736
闹比i
闹比i 2020-12-02 13:56

Is it possible to extend an generic class for a specialised/constructed generic type? I would like to extend Int Arrays with a method to calculate the sum of its elements.

7条回答
  •  温柔的废话
    2020-12-02 14:38

    Managed to get something working in an extensible, generic fashion without abusing the type system too badly, however it has some limitations.

    protocol Addable {
        func +(lhs: Self, rhs: Self) -> Self
        class var identity: Self { get }
    }
    
    extension Int : Addable {
        static var identity: Int { get { return 0 } }
    }
    
    extension String : Addable {
        static var identity: String { get { return "" } }
    }
    
    extension Array {
        func sum() -> U? {
            let s: U? = U.identity
            return self.sum(s)
        }
    
        func sum(start: U?) -> U? {
            return reduce(start) { lhs, rhs in
                switch (lhs, rhs) {
                case (.Some(let left), let right as U):
                    return left + right
                default:
                    return nil
                }
            }
        }
    }
    

    Specifically: with this solution, type inferencing won't work on the no-parameter sum() method, so you have to either annotate the expected return type or give it a starting value (from which it can infer the type).

    Note also that this returns a value of Optional type: if for any reason a sum of the expected type cannot be computed from the array, it returns nil.

    To illustrate:

    let int_array = Array(1...10)
    
    let x: Int? = int_array.sum() // result: {Some 55}
    let x2 = int_array.sum(0) // result: {Some 55}
    let x3 = int_array.sum() // Compiler error because it can't infer type
    
    
    let string_array = ["a", "b", "c"]
    
    let y: String? = string_array.sum() // result: {Some "abc"}
    let y2 = string_array.sum("") // result: {Some "abc"}
    
    let y3: Int? = string_array.sum() // result: nil  (can't cast String to Int)
    let y4 = string_array.sum(0) // result: nil  (can't cast String to Int)
    
    
    let double_array = [1.3, 4.2, 2.1]
    
    let z = double_array.sum(0.0) // Compiler error because we haven't extended Double to be Addable
    

提交回复
热议问题