【问题标题】:Why using Self as return type is not considered as the protocol's constraint?为什么使用 Self 作为返回类型不被视为协议的约束?
【发布时间】:2021-04-04 10:45:39
【问题描述】:

这是 Swift 中有效的协议声明:

protocol Proto1: class {
    func method1() -> Self
    func method2() -> [Proto1]
}

但这不是:

protocol Proto2: class {
    func method1(param: Self)
    func method2() -> [Proto2]
}

错误信息是:

Protocol 'Proto2' 只能用作通用约束,因为它 有 Self 或关联的类型要求

看来,当使用Self 作为函数的返回类型时,Swift 并不认为这是对正在定义的协议的约束,因此可以使用协议本身作为函数的返回类型。但是当使用Self作为函数的参数类型时,行为就完全不同了。

我想知道为什么会有这样的差异?

【问题讨论】:

    标签: ios swift swift-protocols associated-types


    【解决方案1】:

    因为将Self 作为方法的参数类型没有用处。假设你可以做:

    protocol P {
        func f(_ x: Self)
    }
    
    class A: P {
        func f(_ x: Self) {
            // not relevant
        }
    }
    
    class B: A { }
    

    现在假设我有:

    func g(x: A) {
        // what can I do with x?
    }
    

    事实上,没有办法调用x.f。因为我可以将B 的实例传递给x,在这种情况下x.f 将接受Bx 可能是 A 的任何子类的实例,我在编译时无法知道,所以我不知道我可以传递给 x.f 什么。


    将其与用作返回类型的Self 进行比较:

    protocol P {
        func f() -> Self
    }
    
    // Implementation:
    class A: P {
        func f() -> Self {
            self
        }
    }
    
    class B: A { }
    
    func g(x: A) {
        let foo: A = x.f()
    }
    

    在这里,我们知道我可以至少x.f 的返回值分配给A 类型的变量。即使xB 的一个实例,这意味着f 返回一个B,我们仍然可以将它分配给A 类型的变量。

    【讨论】:

    • 感谢@Sweeper。我明白你的意思了。返回类型和参数类型的不同之处在于 Swift 编译器需要知道参数类型,以便它可以确定函数体中的代码是否以正确的方式访问或操作参数值。返回类型实际上也很重要,但不是返回它的函数,而是接收它的函数(即调用者)。这似乎是 Swift 编译器以不同方式处理它们的原因。
    • 顺便说一句,您关于 Self 不应用作参数类型的说法可能不正确。请参阅此discussion 中的示例。我刚刚提交了一个与该讨论相关的问题here。如果您也可以看看这个问题,将不胜感激:)
    • @rayx 好吧,该讨论是关于 Self 作为 initialiser 的参数,它没有我在回答中谈到的“无用”问题.我已经编辑了答案,专门说“方法”。感谢您指出这一点。
    • 再想一想,为什么可以将 A 的实例或其子类传递给 g(x:) 是个问题? g(x:) func 中的代码可以将所有这些都作为 A 的实例来处理。这是 OOP 中非常常见的方法。也就是说,我确实发现docSelf 只能用作返回类型或方法体。无论如何,混合Self 和子类似乎充满了陷阱,应该避免。
    • @rayx 因为子类就是这样工作的? g 中的代码无法将它们全部处理为将A 作为参数类型正是因为Self 的语义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多