为什么我不能像 Swift 中的接口一样使用这个协议?



我想使用一个协议作为接口,但在Swift中解决它时遇到了问题。有人能理解这个错误并为我指明正确的方向吗?

也许我对协议的想法完全不恰当。

这是示例代码:

protocol State {
associatedtype U: State
static func fromString(_: String) -> U
}
class ConcreteState1: State {
static func fromString(_ value: String) -> ConcreteState1 {
return ConcreteState1()
}
}
protocol Loader {
associatedtype T: State
func load(completion: (Result<T.U, Error>) -> Void)
}
extension Loader {
func load(completion: (Result<T.U, Error>) -> Void) {
let value = T.fromString("")
completion(.success(value))
}
}
class ConcreteState1Loader: Loader {
typealias T = ConcreteState1
}
// Abstraction to deal with various types of state
var mainState: (any State)?
// Needs to be an abstraction using the protocol because the specific loader is injected
// This is just a simplified reproduction of the issue
var loader: any Loader = ConcreteState1Loader()
// ERROR: Member 'load' cannot be used on value of type 'any Loader'; consider using a generic constraint instead
loader.load { result in
if let state = try? result.get() {
mainState = state
}
}

这里的方法'load'不能使用,因为Protocol Loader是泛型的,它与另一个协议相关联。具体状态应该在具体加载器中定义,就像在ConcreteState1Loader中定义的一样。

因此,如果您应该向下转换Loader

(oader as! ConcreteState1Loader).load { result in
if let state = try? result.get() {
mainState = state
}
}

这就是我想到的。我将State协议转换为类,并将静态方法更改为类方法,以便可以覆盖它。我依赖一个新的GenericLoader,它可以使用这些类方法转换类型。

如果有更好、更聪明的方法,请告诉我。

class State {
class func fromString(_: String) -> State {
fatalError("must be implemented in derived class")
}
}
class ConcreteState1: State {
override class func fromString(_: String) -> State {
return ConcreteState1()
}
}
protocol Loader {
func load(completion: (Result<State, Error>) -> Void)
}
class GenericLoader<T: State>: Loader {
func load(completion: (Result<State, Error>) -> Void) {
let value = T.fromString("")
completion(.success(value))
}
}
// Abstraction to deal with various types of state
var mainState: State?
// Needs to be an abstraction using the protocol because the specific loader is injected
// This is just a simplified reproduction of the issue
var loader: Loader = GenericLoader<ConcreteState1>()
loader.load { result in
if let state = try? result.get() {
mainState = state
}
}

最新更新