带有重载泛型方法的重载解决问题

时间:2015-01-03 16:44:53

标签: generics swift overload-resolution

我确实遇到了重载泛型方法的问题。考虑这个例子:

class Foo {

    func foo<T>(v: T) {
        println("foo<T>(v: T)")
    }
    func foo<T>(x: Int, v: T) {
        println("foo<T>(x: Int, v: T)")
    }

}


let foo = Foo()
foo.foo("")
foo.foo(1, "")
foo.foo(x: 1, "")
foo.foo(x: 1, v: "")

这会将以下内容输出到控制台:

  

foo(v:T)
  foo(v:T)
  foo(v:T)
  foo(v:T)

也就是说,无论如何,只从重载决策中选择方法foo<T>(v: T)。注意:编译器将元组(:Int, :String)传递给第一个方法,而不是调用第二个方法。

这是预期的行为吗?

嗯,我怀疑:我确实承认类型参数可以包含一个元组,但是我认为函数foo<T>(x: Int, v: T)是一个更好的匹配。

不幸的是,我无法找到解决方法。通用方法foo<T>(v: T)似乎通过传递元组来适应所有内容 - 无论存在什么其他重载。

更新

在Xcode V6.1.1(6A2008a)中,与方法(绑定到特定类型的函数)相反,重载的函数按预期解析:

请考虑以下代码段:

func foo<T>(o: T) {
    println("foo<T>(:T), \(o)")
}

func foo<T>(x: Int, o: T) {
    println("foo<T>(:Int, :T), \(x), \(o)")
}

foo(1)
foo(1, "a")

这会将以下内容输出到控制台:

  

foo(:T),1
   foo(:Int,:T),1,a

这让我相信这是编译器中的一个问题。我提交了一份错误报告。

2 个答案:

答案 0 :(得分:1)

尝试在第一个参数之前删除“x:”,如:

foo.foo(1, v: "")

<强>已更新

对于方法,默认行为是:

  

具体来说,默认情况下,Swift在方法中为第一个参数名称提供一个本地参数名称,并默认为第二个和后续参数名称提供本地和外部参数名称。

功能

  

如果希望函数用户在调用函数时提供参数名称,请为本地参数名称定义每个参数的外部参数名称。您在它支持的本地参数名称之前编写外部参数名称,用空格分隔:...

文件还在功能中说:

  

如果为参数提供外部参数名称,则在调用该函数时必须始终使用该外部名称。

看起来这对于方法来说是正确的,这就是foo.foo(1, v: "")仅适用于方法的原因,因为有一个外部参数名称,你必须使用它。

答案 1 :(得分:1)

哈,是的,这是非常违反直觉的。当你有一个通用的命名第二个参数与一个未命名的单个泛型参数时,它似乎是特定的。

一些可能的修复:

当然,您未在示例中尝试的一个案例不是命名x,而是命名v

foo.foo(1, v: "") // prints foo<T>(x: Int, v: T)

或者,如果你抛弃命名参数v

class Foo {

    func foo<T>(v: T) {
        println("foo<T>(v: T)")
    }

    func foo<T>(x: Int, _ v: T) {
        println("foo<T>(x: Int, v: T)")
    }

}

let foo = Foo()
foo.foo("")     // prints foo<T>(v: T)
foo.foo(1, "")  // prints foo<T>(x: Int, v: T)
foo.foo(1, "")  // prints foo<T>(x: Int, v: T)

幽默地说,这翻了一个之前有效的电话来做相反的事情:

foo.foo(1, v: "")  // prints foo<T>(v: T)

或者,您可以为所有

命令参数名称。

class Foo {

    func foo<T>(#v: T) {
        println("foo<T>(v: T)")
    }

    func foo<T>(#x: Int, v: T) {
        println("foo<T>(x: Int, v: T)")
    }

}


let foo = Foo()
foo.foo(v: "")     // prints foo<T>(v: T)
foo.foo(x: 1, v: "")  // prints foo<T>(x: Int, v: T)
foo.foo(x: 1, v: "")  // prints foo<T>(x: Int, v: T)
foo.foo(x: 1, v: "")  // prints foo<T>(x: Int, v: T)