首页 > 解决方案 > 自定义中缀运算符和选项

问题描述

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?
}

这段代码可以编译,甚至可以工作。但为什么?leftright变量是可选的,我不应该先在正文中解开它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?
}

由于我之前提到的原因,现在它无法编译。它希望我先打开选项。
实际上,如果它像“=="))) 那样“正常工作”,那就太好了,因为在这里不必显式地解开选项会很方便。

所以我想了解为什么它在这两种情况下表现不同。

标签: swiftswift5.1

解决方案


这段代码可以编译,甚至可以工作。但为什么?

这仅仅是因为为所有where is声明了一个==运算符,如下所示:Optional<Wrapped>WrappedEquatable

static func == (lhs: Wrapped?, rhs: Wrapped?) -> Bool

TreeNodeEquatable你的第一个代码片段中,所以它可以工作。

在您的第二个代码片段中,您尚未声明=|=对 two 进行操作的运算符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(_:).


推荐阅读