Self 类型的存储变量(特别是子类化时)

2024-05-04

class LinkedNode<T> {
    var value: T
    var next: Self?
    
    required init(_ value: T) {
        self.value = value
    }
}

class DoublyNode<T>: LinkedNode<T> {
    weak var previous: DoublyNode?
    override var next: Self? {
        didSet { next.previous = self }
    }
}

我希望它能像这样编译。但事实并非如此。

存储的属性不能具有协变“Self”类型

我必须重写代码才能使其编译并工作:

class LinkedNode<T> {
    var value: T
    var next: LinkedNode?
    
    required init(_ value: T) {
        self.value = value
    }
}

class DoublyNode<T>: LinkedNode<T> {
    weak var previous: DoublyNode?
    override var next: LinkedNode<T>? {
        didSet { (next as! Self).previous = self }
    }
}

并且在后面的代码中处处每次引用后next属性我必须手动将其转换为 DoublyNode(当我使用 DoublyNode 时),因为它始终具有 LinkedNode 类型。
它是可以管理的,但又烦人又丑陋。


让我演示一下为什么 Swift 不允许这样做。如果它确实允许您使用Self这样,理论上你可以这样做:

let doublyNode = DoublyNode(1)
let linkedNode: LinkedNode<Int> = doublyNode // this assignment should work, right?
linkedNode.next = LinkedNode(2) // "linkedNode" is of type LinkedNode, so Self is LinkedNode, so I can do this assignment, right?

现在会发生什么?这didSet of next in DoublyNode被调用,它尝试访问previous of LinkedNode(2)。事情是,LinkedNode甚至没有previous财产!因此,允许您使用Self这种方式不安全。

我不认为DoublyNode应该继承自LinkedNode根本不。亚历山大的回答很好地解释了这一点,即这违反了LSP https://en.wikipedia.org/wiki/Liskov_substitution_principle。您可以做的一件事是使用协议来关联这两个类:

protocol LinkedNodeProtocol {
    associatedtype Data
    
    var value: Data { get set }
    var next: Self? { get set }
    
    init(_ value: Data)
}

final class LinkedNode<Data>: LinkedNodeProtocol {
    var value: Data
    var next: LinkedNode?
    
    init(_ value: Data) {
        self.value = value
    }
}

final class DoublyNode<Data>: LinkedNodeProtocol {
    var value: Data
    weak var previous: DoublyNode?
    var next: DoublyNode? {
        didSet { next?.previous = self }
    }
    
    init(_ value: Data) {
        self.value = value
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Self 类型的存储变量(特别是子类化时) 的相关文章

随机推荐