用返回非可选值的计算属性覆盖返回可选值的计算属性

Posted

技术标签:

【中文标题】用返回非可选值的计算属性覆盖返回可选值的计算属性【英文标题】:Overriding a computed property that returns an Optional value with one that returns a non-Optional 【发布时间】:2018-06-30 19:43:16 【问题描述】:

在我运行 Swift 4 的 Xcode 9.2 上编译和运行以下代码没有问题:

class ParentWithComputedOptional 
    var computedOptional: Int?  return nil 


class ChildThatUnwraps: ParentWithComputedOptional 
    override var computedOptional: Int  return 10 

请注意,在父级中,computedOptionalInt?,但在子级中,它被覆盖为 Int。此外,必须指定 override 关键字才能编译代码。这已在 Playground 和适当的项目上进行了测试。

这是预期的行为吗?如果是,Apple 的文档中是否有针对这种情况的相关页面?

【问题讨论】:

您发现了一个有趣的发现。我认为这很有意义,因为每当您使用父类型时,您都期望非 nil 或 nil,这是由始终提供非 nil 的子类型来实现的。它不会以相反的方式工作(在父级中是非可选的,在子级中是可选的)。在某种程度上,这让我想起了 Liskov 替换原则(它更关注语义而不是语法,但仍然适用于 IMO)。我没有发现语言指南中明确提到了这种“现象”,但我希望 Swift 专业人士能过来并指出我们正确的页面:) @dr_barto 这个问题是当访问ChildThatUnwraps 的实例时,您不会解开computedOptional,而如果您确实必须执行解开将对象转换为 ParentWithComputedOptional - 即使它是同一个属性。 我的错,你当然是对的。这让它变得更有趣...... 哦。它不仅适用于computed properties,也适用于functions 【参考方案1】:

官方语言指南中似乎没有记录这种特殊的覆盖情况,但在 Swift 的 changelog 中提到了 4.0 版本(查找 SR-1529)。


这个主题值得一些额外的信息:

实际上,此行为不仅限于可选项,还适用于其他covariant 类型,只要被覆盖的属性是派生类中的计算只读属性。 例如,以下代码也将在 Swift 4.1 中编译。

class Animal 
class Koala: Animal 

class Foo 
  var x: Animal  return Animal() 

class Bar: Foo 
  override var x: Koala  return Koala() 

这是一种不违反Liskov substitution principle 的极端情况,因为基类的属性是只读的计算属性。因此,如果Bar 的实例被保存在Foo 类型的变量中,则无法改变其x 属性,以便在将对象向下转换为Bar 类型的变量。

【讨论】:

以上是关于用返回非可选值的计算属性覆盖返回可选值的计算属性的主要内容,如果未能解决你的问题,请参考以下文章

Swift:XCTest 会修改状态吗?可以返回可选值的测试函数的约定是啥?

我们可以为返回可选值的 swift 函数添加 @objc 吗?

组成必需值和可选值的期货

可选类中的可选属性 VS 可选字典中的可选值

为啥你可以在 Swift 中为可选类型分配非可选值?

如何编写处理可选值的字典扩展