Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 为什么使用Self作为返回类型不被视为协议的约束?_Ios_Swift_Swift Protocols_Associated Types - Fatal编程技术网

Ios 为什么使用Self作为返回类型不被视为协议的约束?

Ios 为什么使用Self作为返回类型不被视为协议的约束?,ios,swift,swift-protocols,associated-types,Ios,Swift,Swift Protocols,Associated Types,这是Swift中的有效协议声明: protocol Proto1: class { func method1() -> Self func method2() -> [Proto1] } 但这不是: protocol Proto2: class { func method1(param: Self) func method2() -> [Proto2] } 错误消息是: 协议“Proto2”只能用作泛型约束,因为它 具有自身或关联的类型要求

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

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

protocol Proto2: class {
    func method1(param: Self)
    func method2() -> [Proto2]
}
错误消息是:

协议“Proto2”只能用作泛型约束,因为它 具有自身或关联的类型要求

因此,当使用自作为函数的返回类型时,SWIFT不认为这是定义的协议的约束,因此使用协议本身作为函数的返回类型是可以的。但当使用Self作为函数的参数类型时,行为完全不同


我想知道为什么会有这样的区别?

因为将Self作为方法的参数类型是没有用的。假设您可以执行以下操作:

现在假设我有:

func g(x: A) {
    // what can I do with x?
}
事实上,没有办法调用x.f,因为我可以将一个B的实例传递给x,在这种情况下,x.f将接受一个B。x可以是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的变量。即使x是B的实例,这意味着f返回a B,我们仍然可以将其分配给类型a的变量。

谢谢@Sweeper。我明白你的意思。返回类型和参数类型不同,Swift编译器需要知道参数类型,以便确定函数体中的代码是否以正确的方式访问或操作参数值。返回类型实际上也很重要,但不是返回它的函数,而是接收它的函数,即调用方。这似乎就是为什么Swift编译器会以不同的方式处理它们的原因。顺便说一句,您不应该将Self用作param类型的说法可能是不正确的。请参见本文中的示例。我刚刚提出了一个与那次讨论有关的问题。如果你也能看看这个问题,我将不胜感激:@rayx,这个讨论是关于Self作为初始化器参数的,它没有我在回答中提到的无用问题。我已经编辑了答案,特别是关于方法的。感谢您指出这一点。再想想,为什么您可以将a或其子类的实例传递给gx:?在gx:func中的代码可以将它们作为A的实例来处理。这是OOP中非常常见的方法。也就是说,我确实发现Self只能用作返回类型或在方法体中使用。无论如何,混合使用Self和subclass似乎充满了陷阱,应该避免。@rayx,因为子类就是这样工作的?由于Self的语义,g中的代码不能将它们全部作为参数类型处理。
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()
}