Swift:将方法之间的歧义消除为类型的curried函数(仅限< Swift 2.2)

时间:2015-04-17 11:59:31

标签: swift protocols optional

请注意此问题已通过Swift 2.2的发布得到解决 - 请参阅 Swift编程语言一书中的“显式成员表达式”部分。


在swift中,您可以对可能符合或不符合协议的方法进行可选调用:

@objc protocol F {
    optional func f(#p1: String, p2: String) -> String
}

@objc class C: F {
    func f(#p1: String, p2: String) -> String { return "0 \(p1) \(p2)" }
}

let c: F = C()

c.f?(p1: "1", p2: "2") // --> "0 1 2"

或者您也可以选择将方法绑定到本地常量:

if let f = c.f {
    f(p1: "1", p2: "2")
}

这是一种优雅的方式来包装一些代码,这些代码只有在实现方法时才会发生,而不仅仅是调用本身。但请注意,与respondsToSelector:的{​​{1}}不同,可选绑定不会检查命名参数。因此,如果您有两个只在参数名称上有所不同的方法,则会得到NSObjectProtocol编译时错误:

Ambiguous use of 'f'

这是Swift-Obj C互操作性的问题。或者我错过了什么,实际上有一些Swift语法可以消除这两种方法之间的歧义?或者我应该放弃设计使用可选方法的代码,并且只需要多个协议来满足需求的多样性(这可能反过来用很多协议名称来填充类型定义)?

修改

我最初的想法与@objc protocol F { optional func f(#p1: String, p2: String) -> String optional func f(#x: String, y: String) -> String } @objc class C: F { func f(#p1: String, p2: String) -> String { return "0 \(p1) \(p2)" } func f(#x: String, y: String) -> String { return "0 \(x) \(y)" } } let c: F = C() c.f?(p1: "1", p2: "2") // --> "0 1 2" c.f?(x: "1", y: "2") // --> "0 1 2" if let f = c.f { // Ambiguous use of 'f' f(p1: "1", p2: "2") } 下面的答案一致。然而,我现在开始更倾向于他最初的评论:“这似乎是语法中的遗漏。我会报告它。”这样做的原因与引用实例方法的模拟情况有关:类型的curried函数:

Sulthan

这是Swift的一个很好的people are already making good use of this基本功能。

当然你可以对命名参数做同样的事情:

class C {
    func f() -> String { return "I'm a C" }
}

let c = C()
c.f() //--> "I'm a C"

let f = C.f(c)
f() //--> "I'm a C"

再次,与上面的可选方法一样,我不知道如何在没有立即调用的情况下消除'f'和'g'之间的歧义:

class D {
    func g(#x: Int) -> String { return "Gave me \(x)" }
    func g(#y: Int) -> String { return "Give me \(y)" }
}

let d = D()
d.g(x: 5) //--> "Gave me 5"
d.g(y: 15) //--> "Gave me 15"

D.g(d)(x: 5) //--> "Gave me 5"

请注意,类型注释会有所帮助(当然,如果类型被声明为differen):

let g = D.g(d) // Ambiguous use of 'g'
g(x: 5)

但是,编译器会忽略class D { func g(#x: Int) -> String { return "Gave me \(x)" } func g(#y: Double) -> String { return "Give me \(y)" } } let d = D() let g: (x: Int) -> String = D.g(d) g(x: 5) //--> "Gave me 5" 中的参数名称,如果(x: Int)x都是y,则引用仍然不明确...

同样:

Int

即使:

let p = (x: 0, y: 1)
p is (a: Int, b: Int) //--> true

1 个答案:

答案 0 :(得分:2)

我刚检查了Swift语法的相关部分,所以我确信目前没有办法在语法中区分这两个函数。相关部分是

<强>表达式

  

隐式成员表达式→。identifier

无法向标识符添加外部参数。

但是,请注意纯swift中不存在可选方法,它们只是因为Obj-C有它们,所以没有什么理由让Swift对可选方法有特殊的语法。另请注意,即使Obj-C也没有用于检查可选方法是否存在的特殊语法。 Obj-C使用反射 - 调用respondsToSelector将为您提供所需的信息。你可以在Swift中做同样的事情。见What is the swift equivalent of respondsToSelector?