属性声明一个不透明的返回类型,但没有可从中推断基础类型的初始值设定项表达式

dev*_*999 5 protocols swift opaque-types

我有一个协议

protocol doSomethingProtocol {
    associatedtype someType
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个正在实现这个协议的类

class doSomethingClass : doSomethingProtocol {
    typealias someType = Int
}

Run Code Online (Sandbox Code Playgroud)

现在我想使用这个协议作为其他类的参考

class someClass : ObservableObject {

    private var reference : doSomethingProtocol

}
Run Code Online (Sandbox Code Playgroud)

现在我不能这样做,因为doSomethingProtocol有关联类型。所以我决定使用some

class someClass : ObservableObject {

    private var reference : some doSomethingProtocol

    init(){
         reference = doSomethingClass()
    }

}
Run Code Online (Sandbox Code Playgroud)

然而这不起作用。我得到了错误Property declares an opaque return type, but has no initializer expression from which to infer an underlying type。为什么 ?我在类 init 中给它初始化表达式。

但是当我做这样的事情时

class someClass : ObservableObject {

    private var reference : some doSomethingProtocol = doSomethingClass()

    init(){}

}
Run Code Online (Sandbox Code Playgroud)

我没有收到任何错误消息并且它可以编译。为什么,两者有什么区别。

Rob*_*ier 9

现在我不能这样做,因为 doSomethingProtocol 有一个关联类型。所以我决定使用some

这就是你出错的地方。不透明 ( some) 类型解决的问题与具有关联类型的协议完全不同。不透明类型是混凝土。它是一种特定类型,在编译时已知,由函数返回。只是函数的调用者不知道它。编译器完全知道它。

var reference : some DoSomethingProtocol
Run Code Online (Sandbox Code Playgroud)

鉴于此信息,具体类型是什么reference?目前尚不清楚。的行为暗示了这一点init,但并不知道总是如此。(更重要的是,因为这是一个可以覆盖它init并分配其他类型的类。)

你想要做的事情是这样完成的:

private var reference : DoSomethingClass
Run Code Online (Sandbox Code Playgroud)

这定义了 SomeType == DoSomethingClass,并允许 DoSomethingClass 符合 DoSomethingProtocol。

如果您试图避免确定 DoSomethingClass 在这里使用的类型,那是不可能的。为了符合具有关联类型的协议,您必须提供可以在编译时确定的具体类型。

考虑到您遇到的问题,我怀疑 DoSomethingClass 的设计不正确,并且您实际上并不需要此处的 PAT(具有关联类型的协议)。您可能需要一个泛型、组合或可能的闭包。您有可能(尽管不太可能)需要一个橡皮擦。但您不需要不透明的类型。

(请将您的类型大写。在 Swift 中,类型的前导小写是非常混乱的。)