【问题标题】:Swift 3.0: compiler error when calling global func min<T>(T,T) in Array or Dictionary extensionSwift 3.0:在数组或字典扩展中调用全局 func min<T>(T,T) 时出现编译器错误
【发布时间】:2017-01-28 20:42:08
【问题描述】:

从 Swift 2.2 转换到 3.0 后,我的 Array 扩展不再编译,因为它包含对全局标准库函数 min&lt;T&gt;(T,T) 的调用并显示编译器错误 extra argument in call

这是重现错误的简单方法:

extension Array {
    func smallestInt(first: Int, second: Int) -> Int {
        return min(first, second) // compiler error: "Extra argument in call"
    }
}

将相同的函数添加到Dictionary 的扩展时,我得到了同样的错误,而完全相同的代码在其他类型的扩展(例如StringAudioBuffer)中编译得很好:

查看ArrayDictionary的文档,发现Sequence上有实例方法名为public func min() -&gt; Element?public func min(by areInIncreasingOrder: (Element, Element) throws -&gt; Bool) rethrows -&gt; Element?。虽然StringAudioBuffer 都没有任何min(...) 功能。

这可能是我无法调用全局函数的原因吗?编译器无法区分全局func min&lt;T&gt;(T,T)self.min(...) 尽管它们的签名完全不同?

这是错误还是功能?我究竟做错了什么?如何在 Array 扩展内正确调用 min(T,T)

【问题讨论】:

    标签: arrays swift swift3 swift-extensions


    【解决方案1】:

    我认为编译器没有理由不能解析这个函数调用,因此我认为这是一个错误(它已经被归档 - 参见SR-2450)。

    每当尝试调用具有相同名称的顶级函数时,似乎都会发生这种情况,但对于可从给定类型(实例或静态)的相同范围访问的方法或属性的签名明显不同。

    一个更简单的例子是:

    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
        }
    }
    

    在修复之前,一个简单的解决方案是在调用前加上它所在模块的名称,以消除您指的是顶级函数而不是实例函数的歧义。对于标准库,即Swift

    extension Array {
        func smallestInt(first: Int, second: Int) -> Int {
            return Swift.min(first, second)
        }
    }
    

    在 Swift 4 中,编译器对这个错误有更好的诊断(尽管它仍然是一个错误的事实是一个错误 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)
        }
    }
    

    虽然有趣的是编译器现在也会警告尝试调用与 stdlib 顶级函数同名的标准库方法:

    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()
        }
    }
    

    在这种情况下,如警告所述,您可以使用显式 self. 使其静音:

    extension Array where Element : Comparable {
    
        func smallest() -> Element? {
            return self.min()
        }
    }
    

    虽然这个警告真正令人好奇的是它并没有出现扩展到非stdlib定义的函数:

    func foo(_ a: Int) {}
    
    struct Foo {
    
        func foo() {}
    
        func bar() {
            foo() // no warning...
        }
    }
    

    【讨论】:

    • 正确,@Hamish;你打败了我。我立即认出了症状,因为它与我在这里讨论的问题非常相似:stackoverflow.com/a/34107042/341994
    • @matt, Hamish:你们谁知道 Playground 中的模块名称是什么吗?问题出现在这里:stackoverflow.com/questions/42110700/….
    • ... 那么 Swift REPL 呢?
    • @MartinR 有趣的问题!据我所知,playground 在运行时被包裹在它们自己的 Cocoa/Cocoa Touch 应用程序中,所以即使你可以计算出模块名称,我怀疑它在同一个 Playground 的不同运行中是否会保持稳定。关于REPL,我不知道。作为一个正式的问题可能值得问:)
    • @MartinR 如果您有兴趣,在 Swift 4 中,playgrounds 现在有一个模块名称 Playground(而 Swift 4 现在提供了更好的诊断信息,告诉您要使用的模块名称)。虽然对于 REPL,诊断给出的模块名称不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多