Swift 3.0:在数组或字典扩展中调用全局 func min<T>(T,T) 时出现编译器错误 [英] Swift 3.0: compiler error when calling global func min<T>(T,T) in Array or Dictionary extension
问题描述
从 Swift 2.2 转换到 3.0 后,我的 Array
扩展不再编译,因为它包含对全局标准库函数 min
并显示编译器错误extra argument in call
.
这是重现错误的简单方法:
扩展数组{func minimumInt(first: Int, second: Int) ->整数{return min(first, second)//编译器错误:调用中的额外参数"}}
将相同的函数添加到 Dictionary
的扩展时,我得到同样的错误,而完全相同的代码在其他类型的扩展中编译得很好(例如 String
或 AudioBuffer
):
查看Array
和Dictionary
的文档,发现Sequence
上有名为public func min() ->元素?
和 public func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows ->元素?
.而 String
和 AudioBuffer
都没有任何类型的 min(...)
函数.
这可能是我无法调用全局函数的原因吗?编译器无法区分全局 func min
和 self.min(...)
尽管它们具有完全不同的签名?>
这是错误还是功能?我究竟做错了什么?如何在 Array
扩展中正确调用 min(T,T)
?
我看不出编译器为什么不能解决这个函数调用的原因,因此我认为它是一个错误(它已经被提交 - 见SR-2450).
每当尝试调用具有相同名称的顶级函数时,似乎都会发生这种情况,但对于可从给定类型(实例或静态)的相同范围访问的方法或属性的签名明显不同.
一个更简单的例子是:
func foo(_ a: Int) {}结构 Foo {func foo() {}//或静态 func foo() {}, var foo = 0, static var foo = 0功能栏(){foo(2)//错误:传递给不带参数的调用的参数}}
在修复之前,一个简单的解决方案是在调用前加上它所在模块的名称,以消除您指的是顶级函数而不是实例函数的歧义.对于标准库,就是 Swift
:
扩展数组{func minimumInt(first: Int, second: Int) ->整数{返回 Swift.min(第一,第二)}}
<小时>
在 Swift 4 中,编译器对这个错误有更好的诊断(尽管它仍然是一个错误 IMO 的事实):
扩展数组{func minimumInt(first: Int, second: Int) ->整数{//'min' 的使用是指实例方法 'min(by:)'//而不是模块 'Swift' 中的全局函数 'min'//- 使用斯威夫特".引用模块Swift"中的全局函数返回分钟(第一,第二)}}
尽管有趣的是编译器现在也会在尝试调用与 stdlib 顶级函数同名的标准库方法时发出警告:
extension Array where Element : Comparable {func 最小() ->元素?{//使用 'min' 作为对协议 'Sequence' 中实例方法的引用//- 使用自我".消除这个警告//- 使用斯威夫特".引用全局函数返回分钟()}}
在这种情况下,正如警告所说,您可以使用显式的 self.
使其静音:
extension Array where Element : Comparable {func 最小() ->元素?{返回 self.min()}}
虽然这个警告真正令人好奇的是它没有似乎扩展到非标准库定义的函数:
func foo(_ a: Int) {}结构 Foo {函数 foo() {}功能栏(){foo()//没有警告...}}
After converting from Swift 2.2 to 3.0 my Array
extension does not compile anymore, because it contains a call to global standard library function min<T>(T,T)
and shows compiler error extra argument in call
.
Here's a simple way to reproduce the error:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return min(first, second) // compiler error: "Extra argument in call"
}
}
I get the same error when adding the same function to an extension of Dictionary
, while the exact same code compiles just fine in an extension of other types (e.g. String
or AudioBuffer
):
Looking at the documentation of Array
and Dictionary
, I find that there are instance methods on Sequence
named public func min() -> Element?
and public func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
. While both String
and AudioBuffer
do not have any kind of min(...)
function.
Is it possible that this is the reason why I can't call the global function? The compiler can't distinguish between global func min<T>(T,T)
and self.min(...)
although they have completely different signatures?
Is this a bug or a feature? What am I doing wrong? How can I call min(T,T)
correctly inside an Array
extension?
I see no reason why the compiler shouldn't be able to resolve this function call, therefore I would consider it a bug (it has already been filed – see SR-2450).
It seems to occur whenever attempting to call a top-level function with the same name, but unambiguously different signature to a method or property that's accessible from the same scope in a given type (instance or static).
An even simpler example would be:
func foo(_ a: Int) {}
struct Foo {
func foo() {} // or static func foo() {}, var foo = 0, static var foo = 0
func bar() {
foo(2) // error: argument passed to call that takes no arguments
}
}
Until fixed, a simple solution would be to prefix the call with the name of the module in which it resides in order to disambiguate that you're referring to the top-level function, rather than the instance one. For the standard library, that's Swift
:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return Swift.min(first, second)
}
}
In Swift 4, the compiler has a better diagnostic for this error (though the fact that it's still an error is a bug IMO):
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
// Use of 'min' refers to instance method 'min(by:)'
// rather than global function 'min' in module 'Swift'
// - Use 'Swift.' to reference the global function in module 'Swift'
return min(first, second)
}
}
Although what's interesting is that the compiler will now also warn on attempting to call a standard library method with the same name as a stdlib top-level function:
extension Array where Element : Comparable {
func smallest() -> Element? {
// Use of 'min' treated as a reference to instance method in protocol 'Sequence'
// - Use 'self.' to silence this warning
// - Use 'Swift.' to reference the global function
return min()
}
}
In this case, as the warning says, you can silence it by using an explicit self.
:
extension Array where Element : Comparable {
func smallest() -> Element? {
return self.min()
}
}
Although what's really curious about this warning is it doesn't appear to extend to non-stdlib defined functions:
func foo(_ a: Int) {}
struct Foo {
func foo() {}
func bar() {
foo() // no warning...
}
}
这篇关于Swift 3.0:在数组或字典扩展中调用全局 func min<T>(T,T) 时出现编译器错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!