我已经看到了这个Swift Equatable Protocol问题的答案,提到了==
方法必须在全球范围内宣布的方式。
如果我不采用Equatable
,我仍然可以声明==
来测试我的两种类型之间的相等性。
// extension Foo: Equatable {}
func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.bar == rhs.bar
}
struct Foo {
let bar:Int
}
即使Equatable
是Equatable
通过。
Intent myIntentForWhatsapp = new Intent(Intent.ACTION_SEND);
myIntentForWhatsapp.setType("text/plain");
myIntentForWhatsapp.setPackage("com.whatsapp");
myIntentForWhatsapp.putExtra(Intent.EXTRA_TEXT, "Hallo, this is a msg");
try {
activity.startActivity(myIntentForWhatsapp);
} catch (android.content.ActivityNotFoundException ex) {
System.out.println("Whatsapp not installed.");
}
协议如何比仅仅让(我们和)编译器安全地知道我们的类型实现了协议所需的方法的语法糖更多?
为什么必须全局声明运算符实现,即使对于协议也是如此?这是由于调度操作员的某种不同方式吗?
答案 0 :(得分:22)
从Xcode 8 beta 4发行说明:
可以在类型或扩展中定义运算符。例如:
struct Foo: Equatable { let value: Int static func ==(lhs: Foo, rhs: Foo) -> Bool { return lhs.value == rhs.value } }
此类运算符必须声明为
static
(或在类class final
内),并且具有相同的运算符 签名作为他们的全球同行。作为此更改的一部分,运营商要求已声明 协议也必须明确声明static
:protocol Equatable { static func ==(lhs: Self, rhs: Self) -> Bool }
This was discussed on the swift-evolution list recently (2016-01-31 through 2016-02-09 so far).以下是Chris Lattner所说的关于在结构或类范围内声明运算符的内容:
是的,这是一个通常需要的功能(至少对称运算符)。在类声明中动态调度运算符也很有用。我不认为我们有一个坚定的建议,即确定名称查找的工作原理。
后来(回复Haravikk):
名称查找问题是什么?你的意思是Foo == Foo的运算符存在于多个位置的情况吗?
是。名称查找必须具有明确定义的搜索顺序 定义阴影和无效的多重定义规则。
就个人而言,我只是坚持我们现在拥有的东西,即将特定类/结构中的运算符实现视为全局 无论如何定义并在声明相同签名时抛出错误 不止一次。
我们需要多个模块才能定义一个实例 运营商,我们需要运营商扩展,我们需要追溯 与任何其他成员一样,符合工作要求。
答案 1 :(得分:7)
操作符函数被定义为具有函数的全局函数 与要重载的运算符匹配的名称。
该函数是全局定义的,而不是作为一个方法 目标类或结构,以便它可以用作中缀运算符 在目标类或结构的现有实例之间。
我用通用表达式目标类或结构替换引号中具体结构(Vector2D
)的名称
答案 2 :(得分:7)
它的实现需要在全局范围内声明,这使得它看起来是偶然的和不同于协议,即使采用Equatable也是如此。
每个协议都是如此,无论是需要全局函数,类方法还是实例方法。您总是可以独立于是否存在需要它的协议来实现。
Equatable协议如何比语法糖更能让我们(我们和)编译器安全地知道我们的类型实现了协议所需的方法?
那不是糖。这是协议的定义和协议的整个要点。它告诉你这种类型可以应用这些东西。
为什么必须全局声明运算符实现,即使对于协议也是如此?这是由于调度操作员的某种不同方式吗?
因为那是Swift的语法。运算符函数实现必须是全局函数。 Swift团队一直有兴趣改变它以使其更加一致,但今天这就是Swift的工作方式。
答案 3 :(得分:1)
之前有点麻烦,因为您需要手动执行Equatable
的实现。尽管Rob Napier提出了一个好的观点,那就是协议的目的。
但是不再了,也就是说,通过一致性,您将获得 Automated Synthesis ,并且不再需要样板代码。
struct Country: Equatable {
let name: String
let capital: String
var visited: Bool
}
就是这样! 编译器将完成其余工作。
let france = Country(name: "France", capital: "Paris", visited: true)
let spain = Country(name: "Spain", capital: "Madrid", visited: true)
if france == spain { ... } // false
话虽这么说,但仍然可以覆盖==
函数的实现。
有关更多信息,请参见here
答案 4 :(得分:0)
在Swift标准库中,定义了'=='运算符。它没有比较的一侧或另一侧的关联性,并且在整个Swift运算符顺序中具有编号优先级。如果你在'import Swift'上点击Swift,你可以检查这个
infix operator == {
associativity none
precedence 130
}
对于Int,该库已经将Int / Int8 / Int16 / Int32 / Int64作为Equatable:
public func ==(lhs: Int, rhs: Int) -> Bool
和许多其他类型一样。
Int在扩展中成为Hashable(在哪里符合该协议,你需要创建一个var hashValue:Int {get},它会随着app的每次执行而改变:
extension Int : Hashable {
public var hashValue: Int { get }
}
运算符'=='和协议通常需要在顶层的struct / enum / class之外声明,因为你正在扩展语言,现在,这就是编译的快捷方式;所有Swift的运算符都是在全局范围内定义的属性。
对于你的'Foo',你通过添加func:
采用了Equatablefunc ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.bar == rhs.bar
}
使用协议中的“Self”局部变量:
public protocol Equatable {
public func ==(lhs: Self, rhs: Self) -> Bool
}