首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在类层次结构中正确地实现平等协议?

如何在类层次结构中正确地实现平等协议?
EN

Stack Overflow用户
提问于 2016-10-07 05:08:10
回答 4查看 10.6K关注 0票数 16

我试图在基类中实现==操作符(来自Equatable),在Swift 3中实现它的子类。所有的类都只在Swift中使用,所以我不想涉及NSObjectNSCopying协议。

我从一个基类和一个子类开始:

代码语言:javascript
复制
class Base {
    var x : Int
}

class Subclass : Base {
    var y : String
}

现在,我想将Equatable==运算符添加到Base中。看起来很简单。从文档中复制==操作符签名:

代码语言:javascript
复制
class Base : Equatable {
    var x : Int

    static func == (lhs: Base, rhs: Base) -> Bool {
        return lhs.x == rhs.x
    }
}

到目前一切尚好。下面是子类:

代码语言:javascript
复制
class Subclass : Base {
    static override func == (lhs: Base, rhs: Base) -> Bool {
        return true
    }
}

但这会导致一个错误:

运算符函数覆盖“最终”运算符函数。

好的。经过一些研究(还在学习Swift 3),我了解到可以用static替换class,以指示可以重写类型方法。

因此,我尝试将static更改为class in Base

代码语言:javascript
复制
class Base : Equatable {
    var x : Int

    class func == (lhs: Base, rhs: Base) -> Bool {
        return lhs.x == rhs.x
    }
}

但这导致了一个新的错误:

非最终类'Base‘中声明的运算符'==’必须是'final‘。

呃。这比应该要复杂得多。

如何在基类和子类中正确地实现Equatable协议和==操作符?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-10-07 05:08:10

经过大量的研究和尝试,我终于想出了一个可行的解决方案。第一步是将==操作符从类内移到全局范围。这修复了有关staticfinal的错误。

对于基类,这变成了:

代码语言:javascript
复制
func == (lhs: Base, rhs: Base) -> Bool {
    return lhs.x == rhs.x
}

class Base : Equatable {
    var x : Int
}

对于子类:

代码语言:javascript
复制
func == (lhs: Subclass, rhs: Subclass) -> Bool {
    return true
}

class Subclass : Base {
    var y : String
}

现在剩下的唯一部分是弄清楚如何从子类的==运算符调用基类的==运算符。这使我找到了最后的解决办法:

代码语言:javascript
复制
func == (lhs: Subclass, rhs: Subclass) -> Bool {
    if lhs.y == rhs.y {
        if lhs as Base == rhs as Base {
            return true
        }
    }

    return false
}

第一个if语句将导致对基类中的==操作符的调用。

最后的解决办法:

Base.swift:

代码语言:javascript
复制
func == (lhs: Base, rhs: Base) -> Bool {
    return lhs.x == rhs.x
}

class Base : Equatable {
    var x : Int
}

Subclass.swift:

代码语言:javascript
复制
func == (lhs: Subclass, rhs: Subclass) -> Bool {
    if lhs.y == rhs.y {
        if lhs as Base == rhs as Base {
            return true
        }
    }

    return false
}

class Subclass : Base {
    var y : String
}
票数 18
EN

Stack Overflow用户

发布于 2019-01-13 14:54:41

根据其他答案,我想出了这样的答案:

代码语言:javascript
复制
class Base : Equatable {
    var x : Int
    static func == (lhs: Base, rhs: Base) -> Bool {
        return lhs.x == rhs.x
    }
}

class Subclass : Base {
    var y : String
    static func == (lhs: Subclass, rhs: Subclass) -> Bool {
        return lhs.y == rhs.y && (lhs as Base) == (rhs as Base)
    }
}
票数 6
EN

Stack Overflow用户

发布于 2018-01-09 10:03:33

我知道这个问题发布已经有一段时间了,但我希望我的答案能有所帮助。

TLDR --而不是试图覆盖==,而是提供一个自定义比较方法,让==调用它,并在需要时重写自定义比较方法。

所以你说

所有的类都将只在Swift中使用,所以我不想涉及NSObjectNSCopying协议。

但是,如果要子类NSObject,您将如何编写自定义比较方法?你会覆盖isEqual(Any?),对吧?如果您试图在子类中遵循Equatable协议,编译器将抱怨“协议Equatable的冗余一致性”,因为NSObject已经符合Equatable

这给我们提供了一些关于NSObject如何处理这个问题的提示--它提供了一个定制的比较方法isEqual(Any?),在==中调用它,如果需要的话,它的子类可以覆盖它。您也可以在您自己的基类中这样做。

让我们来做一些实验(在Swift 4中)。定义一些类

代码语言:javascript
复制
class Grandpa: Equatable {
    var x = 0

    static func ==(lhs: Grandpa, rhs: Grandpa) -> Bool {
        return lhs.isEqual(to: rhs)
    }

    func isEqual(to object: Any?) -> Bool {
        guard object != nil && type(of: object!) == Grandpa.self else {
            return false
        }
        let value = object as! Grandpa
        return x == value.x
    }
}

class Father: Grandpa {
    var y = 0

    override func isEqual(to object: Any?) -> Bool {
        guard object != nil && type(of: object!) == Father.self else {
            return false
        }
        let value = object as! Father
        return x == value.x && y == value.y
    }
}

class Son: Father {
    var z = 0

    override func isEqual(to object: Any?) -> Bool {
        guard object != nil && type(of: object!) == Son.self else {
            return false
        }
        let value = object as! Son
        return x == value.x && y == value.y && z == value.z
    }
}

并编写一些测试代码

代码语言:javascript
复制
let grandpa1 = Grandpa()
let grandpa2 = Grandpa()
let grandpa3: Grandpa? = nil
let grandpa4: Grandpa? = nil
let father1 = Father()
let father2 = Father()
let father3 = Father()
father3.y = 1
let son1 = Son()
let son2 = Son()
let son3 = Son()
son3.z = 1

print("grandpa1 == grandpa2: \(grandpa1 == grandpa2)")
print("grandpa1 == grandpa3: \(grandpa1 == grandpa3)")
print("grandpa3 == grandpa4: \(grandpa3 == grandpa4)")
print("grandpa1 == father1: \(grandpa1 == father1)")
print("father1 == father2: \(father1 == father2)")
print("father1 == father3: \(father1 == father3)")
print("son1 == son2: \(son1 == son2)")
print("son1 == son3: \(son1 == son3)")

运行它,你应该得到

代码语言:javascript
复制
grandpa1 == grandpa2: true
grandpa1 == grandpa3: false
grandpa3 == grandpa4: true
grandpa1 == father1: false
father1 == father2: true
father1 == father3: false
son1 == son2: true
son1 == son3: false
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39909805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档