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

zpqajqem  于 2022-10-31  发布在  Swift
关注(0)|答案(2)|浏览(180)

我想使用一个协议作为接口,但是我在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
    }
}
h43kikqp

h43kikqp1#

无法使用此处的方法“load”,因为协议加载程序是通用的,它与另一个协议相关联。应在具体加载程序中定义具体状态,就像您在ConcreteState1Loader中定义的一样。
所以如果你要向下转换Loader

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

2g32fytz2#

这就是我想到的。我将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
    }
}

相关问题