如何调用更具体的重载方法 [英] How to call the more specific method of overloading

查看:95
本文介绍了如何调用更具体的重载方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



  protocol P {
associatedtype T
func getValue() - > T
}

class Foo:P {
func getValue() - > String {
returnhello
}
}

class Bar {
func test< T:P>(_ o:T){
print(Generic,o.getValue())
}

func test(_ o:Any){
print(Any)



let foo = Foo()
let bar = Bar()
bar.test(foo)

输出:任何



如果我删除任何版本的 test ,则调用通用方法。
Class Foo 符合协议 P ,为什么Swift不选择泛型方法,因为它更具体?有没有办法调用通用的?

解决方案

据我所知,编译器总是偏爱显式类型参数在执行重载分辨率时是通用的。因此,在 test< T:P>(_ o:T) test(_ o:Any) - 后者将是首选,因为它有一个明确的(尽管是抽象的)参数类型,而第一个仅仅是一个占位符。

因此,如果你使第二个重载泛型编译器现在会支持第一次重载,因为它们都没有明确的类型化参数,但第一次重载的约束更加严格:

  class Bar {
func test< T:P>(_ o:T){
print(Generic,o.getValue())
}
$ b func test< T>(_ o:T){
print(Any)
}
}

let foo = Foo ()
let bar = Bar()
bar.test(foo)//泛型hello

按照原样保留重载,为了消除歧义而进行类型转换似乎也是一种可行的解决方案:

  class Bar {
func test< T:P>(_ o:T){
print(Generic,o.getValue())
}

func test(_ o:Any){
print(Any)
}


让foo = Foo()
let bar = Bar()
(bar.test as(Foo) - > Void)(foo)//泛型hello

尽管我会强烈推荐第一种方法,因为它允许您可以更好地了解将选择何种超载(泛型也应该优先于协议类型的参数,只要有可能,由于性能专业化的好处)。

Here is an example playground:

protocol P {
    associatedtype T
    func getValue() -> T
}

class Foo: P {
    func getValue() -> String {
        return "hello"
    }
}

class Bar {
    func test<T: P>(_ o: T) {
        print("Generic", o.getValue())
    }

    func test(_ o: Any) {
        print("Any")
    }
}

let foo = Foo()
let bar = Bar()
bar.test(foo)

This outputs: Any.

If I remove the Any version of test, the generic method is called. Class Foo conforms to protocol P, why does Swift not pick the generic method since it is more specific? Is there a way to call the generic one?

解决方案

From what I understand, the compiler will always favour an explicitly typed parameter over a generic one when performing overload resolution. Thus in the resolution between test<T : P>(_ o: T) and test(_ o: Any) – the latter will be preferred as it has an explicit (albeit abstract) parameter type, whereas the first is merely a placeholder.

Therefore if you make the second overload generic as well, the compiler will now favour the first overload, as they both don't have explicitly typed parameters, but the first overload is more tightly constrained:

class Bar {
    func test<T: P>(_ o: T) {
        print("Generic", o.getValue())
    }

    func test<T>(_ o: T) {
        print("Any")
    }
}

let foo = Foo()
let bar = Bar()
bar.test(foo) // Generic hello

Keeping the overloads as-is, type-casting in order to disambiguate also appears to be a viable solution:

class Bar {
    func test<T: P>(_ o: T) {
        print("Generic", o.getValue())
    }

    func test(_ o: Any) {
        print("Any")
    }
}

let foo = Foo()
let bar = Bar()
(bar.test as (Foo) -> Void)(foo) // Generic hello

Although I would strongly recommend the first approach, as it allows you to reason better about what overload will be chosen (generics should also be preferred in general over protocol-typed parameters wherever possible, due to the performance benefits of specialisation).

这篇关于如何调用更具体的重载方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆