自定义中缀运算符和可选项
Custom infix operators and optionals
class TreeNode: Equatable {
static func ==(lhs: TreeNode, rhs: TreeNode) -> Bool {
lhs.val == rhs.val && lhs.left == rhs.right && lhs.right == rhs.left
}
var val: Int = 0
var left, right: TreeNode?
}
这段代码可以编译甚至可以工作。但为什么? left
和 right
变量是可选的,我不是应该先在 static func ==
的正文中解包吗?
实际上这不是一个等式。如您所见,它更像是某种对称方程。因此,我想为此目的定义具有不同名称的自定义运算符:
infix operator =|=: ComparisonPrecedence
class TreeNode {
static func =|=(lhs: TreeNode, rhs: TreeNode) -> Bool {
lhs.val == rhs.val && lhs.left =|= rhs.right && lhs.right =|= rhs.left
}
var val: Int = 0
var left, right: TreeNode?
}
由于我之前提到的原因,现在它无法编译。它要我先打开选项。
实际上,如果它像“==”)那样“正常工作”会很棒))因为不必显式地解开可选项在这里会很方便。
所以我想了解为什么它在这两种情况下表现不同。
This code compiles and even works. But why?
只是因为有一个 ==
operator 为所有 Optional<Wrapped>
声明,其中 Wrapped
是 Equatable
,像这样:
static func == (lhs: Wrapped?, rhs: Wrapped?) -> Bool
TreeNode
在您的第一个代码片段中是 Equatable
,所以它有效。
在您的第二个代码片段中,您没有声明对两个 TreeNode?
进行运算的 =|=
运算符。您可以通过将其置于全局范围内来做到这一点...
func =|= (lhs: TreeNode?, rhs: TreeNode?) -> Bool {
switch (lhs, rhs) {
case (nil, nil): // both nil
return true
case (let x?, let y?): // both non-nil
return x =|= y // compare two non-optional tree nodes
default:
return false
}
}
或编写 Optional
扩展名:
extension Optional where Wrapped == TreeNode {
static func =|= (lhs: Wrapped?, rhs: Wrapped?) -> Bool {
switch (lhs, rhs) {
case (nil, nil): // both nil
return true
case (let x?, let y?): // both non-nil
return x =|= y // compare two non-optional tree nodes
default:
return false
}
}
}
但正如 Leo Dabus 所说,我只是遵循 Equatable
而不是创建您自己的运算符。符合现有协议允许您将 TreeNode
与标准库中的许多 API 一起使用,例如 Array.contains(_:)
.
class TreeNode: Equatable {
static func ==(lhs: TreeNode, rhs: TreeNode) -> Bool {
lhs.val == rhs.val && lhs.left == rhs.right && lhs.right == rhs.left
}
var val: Int = 0
var left, right: TreeNode?
}
这段代码可以编译甚至可以工作。但为什么? left
和 right
变量是可选的,我不是应该先在 static func ==
的正文中解包吗?
实际上这不是一个等式。如您所见,它更像是某种对称方程。因此,我想为此目的定义具有不同名称的自定义运算符:
infix operator =|=: ComparisonPrecedence
class TreeNode {
static func =|=(lhs: TreeNode, rhs: TreeNode) -> Bool {
lhs.val == rhs.val && lhs.left =|= rhs.right && lhs.right =|= rhs.left
}
var val: Int = 0
var left, right: TreeNode?
}
由于我之前提到的原因,现在它无法编译。它要我先打开选项。
实际上,如果它像“==”)那样“正常工作”会很棒))因为不必显式地解开可选项在这里会很方便。
所以我想了解为什么它在这两种情况下表现不同。
This code compiles and even works. But why?
只是因为有一个 ==
operator 为所有 Optional<Wrapped>
声明,其中 Wrapped
是 Equatable
,像这样:
static func == (lhs: Wrapped?, rhs: Wrapped?) -> Bool
TreeNode
在您的第一个代码片段中是 Equatable
,所以它有效。
在您的第二个代码片段中,您没有声明对两个 TreeNode?
进行运算的 =|=
运算符。您可以通过将其置于全局范围内来做到这一点...
func =|= (lhs: TreeNode?, rhs: TreeNode?) -> Bool {
switch (lhs, rhs) {
case (nil, nil): // both nil
return true
case (let x?, let y?): // both non-nil
return x =|= y // compare two non-optional tree nodes
default:
return false
}
}
或编写 Optional
扩展名:
extension Optional where Wrapped == TreeNode {
static func =|= (lhs: Wrapped?, rhs: Wrapped?) -> Bool {
switch (lhs, rhs) {
case (nil, nil): // both nil
return true
case (let x?, let y?): // both non-nil
return x =|= y // compare two non-optional tree nodes
default:
return false
}
}
}
但正如 Leo Dabus 所说,我只是遵循 Equatable
而不是创建您自己的运算符。符合现有协议允许您将 TreeNode
与标准库中的许多 API 一起使用,例如 Array.contains(_:)
.