如何在Swift中消除仅在参数名称上有差异的函数歧义

6

我有以下功能:

func moveThing(thing: AnyObject, toLeft length: Int) {}
func moveThing(thing: AnyObject, toRight length: Int) {}

然而,当我将其中一个函数作为参数传递时,编译器会报错:"moveThing的使用不明确"

func exec(function: (AnyObject, Int) -> ()) {}
exec(moveThing) // Apparently ambiguous
exec(moveThing as (AnyObject, toLeft: Int) -> ()) // Still ambiguous

如何解决歧义问题?


可能是Swift-将重载函数分配给变量的重复问题。 - Airspeed Velocity
你为什么想这样做呢?为什么不使用moveThingLeft和moveThingRight?如果您能解决歧义,您打算如何使用它? - holroy
这实际上是现有Objective-C API的端口。我可以通过使用选择器“moveThing:toLeft:”和“moveThing:toRight:”轻松消除歧义。然而,如果它是以Swift为目标设计的,命名可能会不同。此外,苹果经常这样做,例如在UITableViewDataSource中,几个方法以tableView(UITableView,XXX:NSIndexPath)开头。 - Guoye Zhang
3个回答

3

Swift进化提案SE-0021通过允许 moveThing(_:toLeft:) 来消除这些函数的歧义,并在Swift 2.2中实现了该功能。


1

我知道这是一个旧的帖子,但最近我遇到了类似的情况。可能会对某些人有所帮助。


简而言之

最终,我通过将方法调用包装在闭包中来解决了这个问题,就像这样:

let cancel: (Text) -> Alert.Button = { .cancel($0) }



冗长的解释

当我输入Alert.Button.cancel (来自SwiftUI框架)时,自动完成会显示以下选项:

cancel(action: (() -> Void)?) // 1
cancel(label: Text) // 2
cancel() // 3
cancel(label: Text, action: (() -> Void)?) // 4

自然地,我认为这段代码应该可以工作:
let cancel: (Text) -> Alert.Button = Alert.Button.cancel(_:)

然而,编译器报错:无法将类型 '((() -> Void)?) -> Alert.Button' 转换为指定类型 '(Text) -> Alert.Button'。显然,它将该签名翻译成了方法1而不是方法2。

事实证明,方法2实际上并不存在。查看Alert.swift中的实际声明,我们发现:

public static func cancel(_ label: Text, action: (() -> Void)? = {}) -> Alert.Button
public static func cancel(_ action: (() -> Void)? = {}) -> Alert.Button

所以,cancel(label:)是由自动补全从cancel(_:action:)中生成的,因为参数action有一个默认值。
结论:我犯了一个错误,认为自动补全显示的是单个方法声明。如果编译器告诉你方法签名与你期望的不匹配,请检查方法的声明。

0
一个有趣的问题!我认为现在你还不能这样做,因为参数名称似乎不是函数引用名称的一部分,尽管我在苹果的参考文档中没有找到任何明确规定这一点的内容。
当然,对于这个特定的例子,你可以使用...

exec({ moveThing($0, toLeft: $1) } )
exec({ moveThing($0, toRight: $1) } )

但我明白你想要用简化的例子来说明。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接