You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中Completion Handler为何需添加下划线字符才能编译?

为什么Swift闭包参数需要加下划线才能编译?

这个问题其实涉及到Swift中闭包和普通函数的参数语法差异,我来给你掰扯清楚:

核心原因:闭包参数默认没有外部标签

Swift里,普通函数的参数可以同时有外部参数名(调用时用来标注,提升可读性)和内部参数名(函数内部使用),比如:

func calculateSum(a: Int, b: Int) -> Int { return a + b }
// 调用时可以写 calculateSum(a: 1, b: 2)

但闭包的参数列表不一样——它默认没有外部参数名,你定义闭包类型时写的参数名称,仅仅是闭包内部可以使用的内部参数名,不能像普通函数那样添加外部标签的语法(比如results: Array<Any>这种写法,Swift会误以为你要定义外部标签,而闭包不支持这个)。

你的代码为什么会报错?

你尝试写的这个版本:

func searchForLocation(name: String, completion: @escaping (results: Array<Any>, error: NSError) -> ()) { }

这里的results:和error:被Swift识别为试图给闭包参数添加外部标签,但闭包类型不允许这种语法,所以编译直接失败。

下划线的作用是什么?

你添加的下划线_,其实是显式声明这个闭包参数没有外部参数名——虽然这是闭包的默认行为,但写出来能让代码意图更清晰:告诉任何读代码的人(包括你自己),调用这个闭包的时候不需要写参数标签。

其实你也可以不用下划线,直接写内部参数名,比如:

func searchForLocation(name: String, completion: @escaping (results: [Any], error: NSError?) -> Void) { }

这个代码是可以正常编译的,但要注意:调用闭包的时候绝对不能写results:或error:标签,只能直接传值。比如在函数内部调用闭包时,必须写:

completion(myResults, myError)

而不是completion(results: myResults, error: myError)——这才是下划线真正要强调的点。

为什么苹果的方法看起来不一样?

你提到苹果的相关方法,比如URLSession的dataTask(with:completionHandler:):

func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask

这里的闭包参数没有写参数名,但这只是苹果的编码风格选择(因为类型已经足够清晰),本质和你的代码逻辑一致。你完全可以给这些闭包参数加上内部名,比如:

func dataTask(with url: URL, completionHandler: @escaping (data: Data?, response: URLResponse?, error: Error?) -> Void) -> URLSessionDataTask

而且苹果的方法里同样不会给闭包参数加外部标签,调用闭包时也不能写参数标签。

总结一下

Swift闭包的设计就是默认不支持外部参数标签,所以你不能像定义普通函数参数那样给闭包参数添加外部标签。下划线只是显式声明这个默认行为,让代码更易读;如果你不想写下划线,直接写内部参数名也是可行的,只要记住调用闭包时不能用参数标签就好。

内容的提问来源于stack exchange,提问作者Supertecnoboff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:17:53