泛型函数内的 Swift Equatable 泛型类型比较

Posted

技术标签:

【中文标题】泛型函数内的 Swift Equatable 泛型类型比较【英文标题】:Swift Equatable Generic type comparison inside generic function 【发布时间】:2017-09-04 22:31:33 【问题描述】:

我有一个像这样的二叉树的Node 类:

class Node<T: Equatable> 
    let value: T
    let left: Node<T>?
    let right: Node<T>?

    init(value: T, left: Node<T>? = nil, right: Node<T>? = nil) 
        self.value = value
        self.left = left
        self.right = right
    

这些值需要是相等的。

我可以这样测试公平性:

let a = Node(value: 8)
let b = Node(value: 7)

let c = a.value > b.value

效果很好,c: true

但是当我编写一个使用节点公平性的通用函数时,我得到了错误:

func isBinaryTree<T>(node: Node<T>) -> Bool 
    if let leftNode = node.left 
        guard leftNode.value < node.value else 
            return false
        
        guard isBinaryTree(node: leftNode) else 
            return false
        
    
    if let rightNode = node.right 
        guard rightNode.value >= node.value else 
            return false
        
        guard isBinaryTree(node: rightNode) else 
            return false
        
    

    return true


let result = isBinaryTree(node: root)

错误:

error: binary operator '<' cannot be applied to two 'T' operands guard leftNode.value < node.value ||`

我不确定为什么编译器似乎不知道为什么 T 值是 Equatable 或者为什么它不认为 leftNode 上的 TTnode

代码:

let d = Node(value: Float(3), left: Node(value: Int(8)) , right: nil)

按预期给出错误。

进一步研究,它与函数无关,因为当我尝试代码时:

let x = Node(value: 3, left: Node(value: 8) , right: nil)
let y = x.value < x.left!.value

我遇到同样的错误

【问题讨论】:

你的例子c不可能,因为你的Node不是Comparable 我觉得把EquatableComparable 混在一起真的很傻。谢谢! 您真正需要的是Comparable 协议。 Equatable 协议只需要实现相等 (==) 函数即可实现一致性。比较函数(如&lt;)只保证由Comparable协议实现。 @richy 在像这样的任意树中,它的可比性没有任何意义。您应该只访问value 并比较它们 【参考方案1】:

在一般情况下,两个 Node 对象是不可比较的。这取决于它们所在的树的类型。例如,如果节点仅被限制为二叉树的有效成员,这是有道理的,但事实并非如此。

幸运的是,您不需要将Node 设为Comparable,您只需要将其value 设为Comparable

class Node<T: Comparable> 
    let value: T
    let left: Node<T>?
    let right: Node<T>?

    init(value: T, left: Node<T>? = nil, right: Node<T>? = nil) 
        self.value = value
        self.left = left
        self.right = right
    


extension Node: Equatable 
    static func == (lhs: Node, rhs: Node) -> Bool 
        return lhs.value == rhs.value
            && lhs.left == rhs.left
            && lhs.right == rhs.right
    


extension Node 
    func isBinarySubTree() -> Bool 
        return left.map  $0.value < self.value  ?? true
            && right.map  self.value < $0.value  ?? true
            && left?.isBinaryTree() ?? true
            && right?.isBinaryTree() ?? true
    

【讨论】:

【参考方案2】:

感谢 Alexander,我的 EquatableComparable 搞混了!节点应该是

class Node<T: Comparable> 
    //...

代码:

let a = Node(value: 8)
let b = Node(value: 7)

let c = a.value > b.value

必须工作,因为编译器知道值是Ints。但在函数中,输入值是未知的。

【讨论】:

以上是关于泛型函数内的 Swift Equatable 泛型类型比较的主要内容,如果未能解决你的问题,请参考以下文章

仅适用于数值类型的泛型类型约束

Apple Swift:String 类型的泛型类型约束仅不起作用

Swift泛型

swift中泛型和 Any 类型

Swift参数及泛型参数参考!

Swift 泛型