在单个参数的情况下,类型推断失败,参数数量可变

时间:2015-03-30 13:07:24

标签: swift

考虑以下代码(我发布这个主要是为了深入了解Swift编译器必须克服的障碍 - 失败本身不太可能影响太多的开发人员):

extension Int {
    static var i: Int { return 5 }
}

func f(#xs: Int...) { // notice the #
    println(xs)
}

f(xs: .i, .i, .i)   // --> [5, 5, 5]
f()                 // --> []
f(xs: 5)            // --> [5]
f(xs: .i)           // --> [5]

func g(xs: Int...) { // no #
    println(xs)
}

g(.i, .i, .i)       // --> [5, 5, 5]
g()                 // --> []
g(5)                // --> [5]
g(.i)               // --> error: '(Int...).Type' does not have a member named 'i'

所以问题是你是否会认为这是一个错误?为此,请考虑问题可能与:

有关
let (xs: Int...) = (.max, .min)
xs // --> [9223372036854775807, -9223372036854775808]

而对于单个元素,编译器不会将parens解释为定义元组(它本身就是语言的一个特征,而不是bug):

let (xs: Int...) = (.max) // error: could not find member 'max'

所以,使用显式类型我们也可以删除parens:

let (xs: Int...) = Int.max
xs // --> [9223372036854775807]

解决方法 (受Airspeed Velocity的启发 - 见下面他/她的好答案)

func h(xs: [Int]) {
    println(xs)
}

func h(x: Int, xs: Int...) {
    h([x] + xs)
}

func h() {
    h([])
}

h(.i, .i, .i)   // --> [5, 5, 5]
h(.i, .i)       // --> [5, 5]
h(.i)           // --> [5]
h()             // --> []

示例用例

import Foundation

public extension NSRegularExpressionOptions { // these are nil literal convertible!

    static var i: NSRegularExpressionOptions { return .CaseInsensitive }
    static var x: NSRegularExpressionOptions { return .AllowCommentsAndWhitespace }
    //  static var IgnoreMetacharacters: NSRegularExpressionOptions { get }
    static var s: NSRegularExpressionOptions { return .DotMatchesLineSeparators }
    static var m: NSRegularExpressionOptions { return .AnchorsMatchLines }
    //  static var UseUnixLineSeparators: NSRegularExpressionOptions { get }
    static var u: NSRegularExpressionOptions { return .UseUnicodeWordBoundaries }
}

public extension String {

    // TODO: implement named capture groups (?<name>pattern)
    func r(options: [NSRegularExpressionOptions]) -> NSRegularExpression {
        return NSRegularExpression(pattern: self, options: reduce(options, nil, |), error: nil)!
    }

    func r(option: NSRegularExpressionOptions, _ options: NSRegularExpressionOptions...) -> NSRegularExpression {
        return r(options + [option])
    }

    func r() -> NSRegularExpression { return r([]) }

    var r: NSRegularExpression { return r([]) }
}

"a\\s+$".r(.m | .i) // --> NSRegularExpression

"a\\s+$".r(.m, .i)  // --> NSRegularExpression

"\\s+$".r(.m)       // --> NSRegularExpression

"\\s+".r()          // --> NSRegularExpression

"\\s+".r            // --> NSRegularExpression

并不是说你一定需要或想要所有这些选项:)事实上,我无法抗拒添加:

public func / (lhs: String, rhs: NSRegularExpressionOptions) -> NSRegularExpression {
    return lhs.r(rhs)
}

public extension NSRegularExpressionOptions {
    static var r: NSRegularExpressionOptions { return .allZeros }
}

"\\s+" / .r             // --> NSRegularExpression
"\\s+$" / .m            // --> NSRegularExpression
"a\\s+$" / (.m | .i)    // --> NSRegularExpression

1 个答案:

答案 0 :(得分:2)

我也在1.2中看到它。但我不确定它是否也是一个错误,尽管编译错误可能会更好。

隐式成员缩写只有在左侧的类型可以完全无误识别时才会启动。但由于函数可以将元组作为参数(即func f(_: Int, _: Int) { }; let x = (1,2); f(x)),因此有两种可能性(IntInt...)。

命名参数或传入多个参数,可以清楚地表明您没有尝试传递(Int...),因此.i左侧的类型是明确的Int隐式成员缩写起作用。

同样,这也有效:func h(_: Int, xs: Int...) { }; h(1, .i)。和g(.i as Int)一样。

如果您尝试这样做,则会收到类似的错误消息:func generic<T>(x: T) { }; g(.i) - 仅仅因为恰好存在一个可能的匹配并不意味着Swift愿意从多种可能性中选择它。

然后,这个论点被这个工作所破坏:func k(i: Int) { }; func k(d: Double) { }; k(.i)。所以也许这是一个错误 - 但无论如何它都值得商榷。