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 类型的存储变量(特别是子类化时) 的相关文章

  • 致命错误:在字典中发现“地理编码地标”类型的重复键。 (Mapbox 地理编码器)

    我引用 这通常意味着要么该类型违反了 Hashable 的要求 要么此类字典的成员在插入后发生了变化 我正在使用 Mapbox Geocoder 当发生此运行时错误时 我的 XCode 将我带到线程 1 0 swift runtime on
  • 从父类调用子类方法

    a doStuff 方法是否可以在不编辑 A 类的情况下打印 B did stuff 如果是这样 我该怎么做 class Program static void Main string args A a new A B b new B a
  • 为什么我的视图仍然以横向呈现?

    我的视图是由导航控制器控制的 因此我将导航控制器支持的方向设置为明确的纵向和纵向UpSideDown 这可以工作 但是如果调用视图时前一个视图处于横向状态 它将以横向方式呈现并保持横向状态 直到设备旋转 如何防止这种情况发生 这是我的代码
  • SKNode 上的 runAction 未完成

    我使用 NSOperation 子类来获取串行执行SKAction正如这个问题中所描述的 如何在 Swift 中子类化 NSOperation 以将 SKAction 对象排队以进行串行执行 https stackoverflow com
  • init 中的 Swift 通用约束

    我有通用的 我希望能够用特定的约束来初始化它 约束仅用于初始化 班里的其他人并不关心 这是一个简化的示例 struct Generic
  • C++中有没有办法让派生类重写基类静态方法?

    我有一个多次派生的基类 B D1 D2 等 在类 B 中 我希望有一个静态方法 getInfo 它返回一个 BaseInfo 类 基本上是一个包含类 B 的默认成员值的类 因此将其设为静态是有意义的 因为不需要特定的实例 现在 有没有办法强
  • iOS 13 beta 外部屏幕上的 OverscanCompensation

    我正在测试一个应用程序的测试版 但遇到了外部屏幕的问题 我们看到应用程序周围有黑色边框 我们之前可以通过设置来纠正它overscanCompensation to none但在 iOS 13 中 该设置根本没有任何效果 我们曾经看到一个错误
  • 为什么使用[ClassName alloc]而不是[[self class] alloc]?

    我正在读马克 达尔林普尔 Mark Dalrymple 的著作在 Mac 上学习 Objective C 仅在协议章节 所以仍然相对较新 并试图弄清楚一些事情 为什么要通过类自己的名称来引用它 如果我有一个叫做Foo 为什么我会想写 比如说
  • Swift 使用哪种通用排序算法?它在排序数据上表现不佳

    我一直在挑选和探索 Swift 标准库sort 其函数为Array类型 令我惊讶的是 我注意到它在已经排序的数据上表现不佳 对数组进行排序Int打乱顺序似乎比对已经排序的同一个数组进行排序快 5 倍 对已打乱顺序的对象数组进行排序比对已按排
  • 迭代 NSOrderedSet

    我正在尝试迭代 NSOrderedSet 的实例 像这样的事情 func myFunc var orderedSet NSOrderedSet array 42 43 44 for n in orderedSet NSLog i n 但是
  • JavaScript 原型继承的缺点是什么?

    我最近看了Douglas Crockford 的 JavaScript 演示 http www yuiblog com blog 2010 02 03 video crockonjs 1 他对 JavaScript 原型继承赞不绝口 仿佛这
  • Swift 中带圆角的 NSWindow

    我想要一个圆角的窗户 但我在每个角落都有一个白点 Code let effect NSVisualEffectView frame NSRect x 0 y 0 width 0 height 0 effect blendingMode be
  • 将 Xcode 的测试类助理编辑器与 Swift 类结合使用

    在 Xcode 中工作时 在助理编辑器中提取单元测试用例通常会很好 目前 我一直在手动选择测试文件 但我看到助理编辑器有一个选项Test Classes 我试图让这个选项自动提取我的测试文件 但我似乎无法让它工作 是否需要某种配置 它不适用
  • Swift 中具有透明背景的按钮边框

    我怎样才能做一个UIButton边框看起来像下图 入门 按钮一样具有透明背景吗 我应该如何使用情节提要来实现这一点 或者如何以编程方式实现这一点 设置backgroundColor to clearColor使按钮透明 例如尝试下面的代码
  • 按范围迭代数组

    我有一个数组 1 2 3 4 5 6 100 我希望将此数组迭代 5 次 具体来说 取数组的前 5 个数字并获取平均值 继续处理接下来的 5 个数字并获取平均值 依此类推 我尝试过多种方法 例如Dequeue和 for 循环但未能获得所需的
  • C++:重写已弃用的虚拟方法时出现弃用警告

    我有一个纯虚拟类 它有一个纯虚拟方法 应该是const 但不幸的是不是 该接口位于库中 并且该类由单独项目中的其他几个类继承 我正在尝试使用这个方法const不会破坏兼容性 至少在一段时间内 但我找不到在非常量方法重载时产生警告的方法 以下
  • 在 swift 中获取 NSImage 的 PNG 表示

    嘿 我在获取 NSImage 对象的 PNG 表示时遇到了一些问题 这就是我正在做的 var imgData NSData coverImgView image TIFFRepresentation var bitmap NSBitmapI
  • 快速将阴影绘制到 uibezierpath

    我有一个奇怪的问题 尽管我确实阅读了很多有关如何执行此操作的教程 但最终结果仅显示贝塞尔线 而不显示任何阴影 我的代码非常简单 let borderLine UIBezierPath borderLine moveToPoint CGPoi
  • Switch 语句,其中 value 为 Int 但 case 可以包含数组 [重复]

    这个问题在这里已经有答案了 我想将我的值数组作为 switch 语句的案例 我有一个值数组 let intValues 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 100 我想使用
  • 我在 NSDateComponentsFormatter 上的 allowedFractionalUnits 上做错了什么?

    基本上我想要的是获取仅以小时表示的时间间隔的值 而不将其四舍五入为完整小时 使用NSDateComponentFormatter https developer apple com library ios documentation Fou

随机推荐