Swift 3.0 closure expression: what if the variadic

2019-06-02 04:18发布

Update at 2016.09.19

There is a tricky, indirect way to use variadic parameters before some other parameters in closure expression parameters list, haha

let testClosure = { (scores: Int...) -> (_ name: String) -> String in
    return { name in
        return "Happy"
    }
}
let k = testClosure(1, 2, 3)("John")

And I found some related issues in bugs.swift.org: SR-2475 SR-494

Original Post

According to the document of Swift 3.0, for a closure expression, "variadic parameters can be used if you name the variadic parameter"(see Closure Expresssion Syntax part). But for Swift 2.x, the description is "Variadic parameters can be used if you name the variadic parameter and place it last in the parameter list", the border part has been removed in Swift 3.0 document, is it means variadic parameter can be a argument of closure expression even it is not at the last place? If so, why the codes below can't compile successfully?

let testClosure = { (scores: Int..., name: String) -> String in
    return "Happy"
}
let k = testClosure(1, 2, 3, "John") // Missing argument for parameter #2 in call

If the argument label can be used in the call, I think the compiler can compile the code above successfully, but in Swift 3.0, closure expression's argument labels are regarded as Extraneous.

Besides, Swift 3.0 document indicates that the parameters in closure expression syntax can be in-out parameters, but Swift 3.0 said that closure expression syntax can use constant parameters, variable parameters, and inout parameters. Why Apple removed descriptions like constant parameters, variable paramters, is it because in Swift 3.0, the parameters can't be var?

Thank you very much for your help!

3条回答
干净又极端
2楼-- · 2019-06-02 04:47

You are able to create a func in Swift 3.0 where the variadic parameter is NOT the last argument. For example...

func addButtons(buttons: UIButton..., completion: (() -> ())? = nil)

I believe it's because the parameter following the variadic parameter is named, and so the func does not confuse the next named argument with more variadic arguments.

addButtons(buttons: button1, button2, button3) {
     //do completion stuff
}
查看更多
Anthone
3楼-- · 2019-06-02 04:53

Variadic parameter have to be last and according to your situation, you can type this:

let testClosure = { (_ name: String, scores: Int...) -> String in
    return "Happy"
}
let k = testClosure("John", 1, 2, 3) 
查看更多
小情绪 Triste *
4楼-- · 2019-06-02 05:05

Still in Swift3 variadic arguments have to be the last parameter in the signature, because despite the fact that in your case the last parameter typed as String can be deduced, there's some cases where not, because of the infinite expansion of variadic argument:

let foo = { (i:Int..., j: Int) -> Int  in
    return j
}
foo(1,2)

...in Swift 3.0, the parameters can't be var?

var params where removed in Swift3 SE-0003 to avoid confusion with inout parameters, because both var and inout params can be assigned inside function, but just inout is reflected back.

 func doSomethingWithVar(var i: Int) {
    i = 2 // change visible inside function.
 }

 func doSomethingWithInout(inout i: Int) {
    i = 2 // change reflected back to caller.
 }

removing var from parameter list, remove the confusion above.

查看更多
登录 后发表回答