为啥传递给函数的协议默认值不会改变,即使函数在子类化时会改变?

Posted

技术标签:

【中文标题】为啥传递给函数的协议默认值不会改变,即使函数在子类化时会改变?【英文标题】:Why does the protocol default value passed to the function not change, even though the function does when subclassing?为什么传递给函数的协议默认值不会改变,即使函数在子类化时会改变? 【发布时间】:2021-01-19 13:00:20 【问题描述】:

我有一个协议,我为其分配了一些默认值:

protocol HigherProtocol 
    var level: Int  get 
    
    func doSomething()


extension HigherProtocol 
    var level: Int  10 
    
    func doSomething() 
        print("Higher level is \(level)")
    

然后我有另一个协议,它符合更高级别的协议,但具有不同的默认值和功能实现:

protocol LowerProtocol: HigherProtocol 

extension LowerProtocol 
    var level: Int  1 
    
    func doSomething() 
        print("Lower level is \(level)")
    

然后我创建一个符合更高层协议的类,然后创建一个符合低层协议的子类:

class HigherClass: HigherProtocol 

class LowerClass: HigherClass, LowerProtocol 

但是,当我实例化这个较低的类时,它会显示一些奇怪的行为:

let lowerClass = LowerClass()

lowerClass.level // is 1

lowerClass.doSomething() // Prints "Lower level is 10" to the console.

默认属性是正确的,但函数的默认实现似乎是两者的混合体。

我想知道这里发生了什么?

【问题讨论】:

【参考方案1】:

您似乎正在尝试使用协议来创建多重继承。它们不是为此而设计的,即使你得到这个工作,你也会被咬几次。协议不能替代继承,无论是多重的还是其他的。 (通常,Swift 更喜欢组合而不是任何形式的继承。)

这里的问题是 HigherClass 符合 HigherProtocol,因此现在有 leveldoSomething 的实现。 LowerClass 继承自它,并希望覆盖这些实现。但是覆盖在协议扩展中,这是未定义的行为。请参阅 Swift 编程语言中的 Extensions:

扩展可以为类型添加新功能,但不能覆盖现有功能。

未定义的行为并不意味着“它不会覆盖”。这意味着“任何事情都可能发生”,包括这种有时会被覆盖有时不会被覆盖的奇怪情况。

(顺便说一句,Objective-C 中的情况类似。在两个不同的类别中实现一个方法会导致不确定调用哪个类别,并且当这种情况发生时没有警告或错误让你。Swift 的优化可以使这种行为更令人惊讶。)

我希望编译器能够检测到这类错误并引发错误,但事实并非如此。您需要重新设计您的系统才能避免这样做。

【讨论】:

【参考方案2】:

协议是存在类型,这就是您感到困惑的原因。您需要公开您的类 Type 的协议类型。在您的情况下,您可以执行 LowerProtocolHigherProtocol 所以现在打印 10。让我们变成这样

let lowerClass: LowerProtocol = LowerClass()

let lowerClass: HigherProtocol = LowerClass()

lowerClass.level // now prints 10

lowerClass.doSomething() // Prints "Lower level is 10" to the console.

【讨论】:

以上是关于为啥传递给函数的协议默认值不会改变,即使函数在子类化时会改变?的主要内容,如果未能解决你的问题,请参考以下文章

调用函数时为啥形参的值不能传给实参

38 py改变函数参数的值关键字参数和参数默认值函数中可变参数将序列中的元素值作为函数对应的参数值传

为啥我们不能通过值传递数组来函数?

子类为啥要调用父类的构造函数

VB 参数传递:按值传递和按地址传递

vue为啥method值不改