问题
I am trying to migrate my code from xcode 8.2 swift 3.0.2 to xcode 9 swift 4, and I have problem with this code:
func test<T0, TRet>(_ fn: (T0) -> TRet) -> Void {
print("foo1")
print(T0.self)
}
func test<T0, T1, TRet>(_ fn: (T0, T1) -> TRet) -> Void {
print("foo2")
print(T0.self)
print(T1.self)
}
let fn2 : (Int, Int) -> Int = { (x:Int, y:Int)->Int in
return x+y
}
test(fn2)
xcode 8.0.2, swift 3.0.2 results with:
foo2
Int
Int
xcode 9, swift 4 results with:
Playground execution failed:
error: MyPlayground.playground:12:1: error: ambiguous use of 'test'
test(fn2)
^
MyPlayground.playground:1:6: note: found this candidate
func test<T0, T1, TRet>(_ fn: (T0, T1) -> TRet) -> Void {
^
Am I missing something? Is there any new feature in swift 4 that causes this error?
Update
I filed a bug at bugs.swift.org as suggested in the comments.
https://bugs.swift.org/browse/SR-6108
回答1:
I ran into the same problem, and stumbled across a workaround that is (for my purposes) nicer than disambiguating via naming. Perhaps it is not even a workaround, just the way things have to be. It's also possible that this is newly-possible in Swift 4.1 (not sure, since I migrated directly from Swift 3 to 4.1)
Change this:
func test<T0, TRet>( fn: (T0) -> TRet) -> Void
...to this...
func test<T0, TRet>( fn: ((T0)) -> TRet) -> Void
(note the extra pair of parens around the T0
callback parameter, which explicitly makes it into a tuple-of-1)
After this change, test(fn2
) compiles and calls the test<T0,T1,TRet>
overload.
It seems that the compiler is able to treat a function with N arguments as a function with one N-way-tuple argument. Hence, both the (T0) -> TRet
and (T0,T1) -> TRet
overloads are candidates for fn2, and the call is ambiguous. Adding 2nd pair of parens ((T0)) -> TRet
limits that overload to an argument with a single parameter or 1-way tuple.
来源:https://stackoverflow.com/questions/46649106/ambiguous-use-on-generic-method-after-migration-to-swift-4