在Swift中使用泛型重载包装函数

时间:2017-10-27 10:29:16

标签: ios swift macos

第一个例子

func foo<T>(_ t: T) -> String {
    return bar(t)
}

func bar<T>(_ t: T) -> String {
    return "Other"
}

func bar<T: StringProtocol>(_ t: T) -> String {
    return "String"
}

foo("") // "Other" // Why not "String"?
bar("") // "String"
bar(1) // "Other"

第二个例子(更复杂)

第一个例子可以通过类型检查解决,但在这个例子中是不可能的。

func foo<T>(_ t: (T) -> String) -> String {
    return bar(t)
}

func bar<T>(_ t: (T) -> String) -> String {
    return "Other"
}

func bar<T: StringProtocol>(_ t: (T) -> String) -> String {
    return "String"
}

foo { (string: String) -> String in return "" } // Other // Why not "String"?
bar { (string: String) -> String in return "" } // String
bar { (int: Int) -> String in return "" } // Other

超载是静态解决的。因为T内部的foo()是不受约束的,所以它用无约束的T来选择bar()的重载。有没有解决方法?

2 个答案:

答案 0 :(得分:0)

根据当前的Swift实现,该函数更专业,意味着它具有约束,这些约束是另一个重载函数的约束的超集;重载将选择更专业的功能。

所以,除了让foo符合StringProtocol之外,我无法想到更好的选择。

关于为什么没有更好的黑客,我想引用Swift documentation,它讨论了如何解决嵌套或更专业的泛型类型。:

  

这相当于运行时重载分辨率,这可能是理想的,   但也有缺点,例如运行时故障的可能性   由于模棱两可和执行如此昂贵的成本   在这些呼叫站点进行操作。当然,这个成本可以减轻   通过上面提到的专业化在热泛型函数中。

     

我们目前的建议是静态决定哪个功能   被调用(基于C ++中使用的类似的部分排序规则),   并避免运行时重载决议。如果这证明是繁重的,我们可以   稍后重新审视决定。

答案 1 :(得分:0)

谈论工作。 你可以这样做。

func foo<T>(_ t: T) -> String {
    if let str = t as? String {
     return bar(str)
    }
    return bar(t)
}

func bar<T>(_ t: T) -> String {
    return "Other"
}

func bar<T: StringProtocol>(_ t: T) -> String {
    return "String"
}

再说起工作。

func foo<T>(_ t: @escaping (T) -> String) -> String {
    if let clsr = t as? (String) -> String {
        return bar(clsr)
    }
    return bar(t)
}

func bar<T>(_ t: (T) -> String) -> String {
    return "Other"
}

func bar<T: StringProtocol>(_ t: (T) -> String) -> String {
    return "String"
}