- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
请注意,随着 Swift 2.2 的发布,这个问题已经得到解决——请参阅 The Swift Programming Language 一书的“Explicit Member Expression”部分。
在 swift 中,您可以对一个方法进行可选调用,该方法可能会或可能不会按照协议(protocol)实现:
@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"
或者您也可以选择将方法绑定(bind)到本地常量:
if let f = c.f {
f(p1: "1", p2: "2")
}
这是一种优雅的方式来包装一些代码,这些代码应该只在实现方法时发生,而不仅仅是调用本身。但是请注意,与 NSObjectProtocol
的 respondsToSelector:
不同,可选绑定(bind)不检查命名参数。因此,如果您有两个仅参数名称不同的方法,就会出现 Ambiguous use of 'f'
编译时错误:
@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")
}
这就是 Swift - Obj C 互操作性的问题。或者我错过了什么,实际上有一些可用的 Swift 语法可以消除这两种方法之间的歧义?或者我应该放弃设计使用可选方法的代码并简单地使用多个协议(protocol)来满足需求的多样性(这可能反过来用大量协议(protocol)名称填充类型定义)?
编辑
我最初的想法是按照下面 Sulthan
的回答。然而,我现在开始更倾向于他原来的评论:“这似乎是语法中的一个遗漏。我会报告它。”这样做的原因与将实例方法引用为该类型的柯里化(Currying)函数的模拟情况有关:
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"
这很好,people are already making good use of this Swift 的基本功能。
当然你也可以对命名参数做同样的事情:
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"
再一次,与上面的可选方法一样,我不知道如何在没有立即调用的情况下区分“f”和“g”:
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
虽然:
let q: (a: Int, b: Int) = (x: 0, y: 1) //--> Error: '(x: Int, y: Int)' is not convertible to '(a: Int, b: Int)`
最佳答案
我刚刚检查了 Swift 语法的相关部分,所以我确定语法中目前没有办法区分这两个函数。相关部分是
表达式
Implicit-member-expression → .identifier
没有办法向标识符添加外部参数。
但是请注意,可选方法在纯 Swift 中并不存在,它们存在只是因为 Obj-C 有它们,所以 Swift 没有什么大的理由为可选方法提供特殊语法。另请注意,即使是 Obj-C 也没有用于检查可选方法是否存在的特殊语法。 Obj-C 使用反射 - 调用 respondsToSelector
将为您提供所需的信息。你可以在 Swift 中做同样的事情。参见 What is the swift equivalent of respondsToSelector?
关于Swift:消除作为类型柯里化(Currying)函数的方法之间的歧义(仅限 < Swift 2.2),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29698580/
我是一名优秀的程序员,十分优秀!