从另一个协议 API 返回具有关联类型的协议

问题描述 投票:0回答:1

我有一个

Session
协议和一个
Output
关联类型:

public protocol SessionAPI {
  associatedtype Output: Equatable
  var output: Output { get }
}

以及返回

String
的协议的具体实现:

public final class StringSession: SessionAPI {
  public typealias Output = String
  public let output: String
}

假设

StringSession
的实现非常复杂并且涉及很多模块,我不想在使用SessionAPI 的类中向那些模块添加依赖项。所以我有另一个使用通用工厂方法出售 StringSessions 的协议:

public protocol SessionFactoryAPI {
  func createStringFactory<T: SessionAPI>() -> T where T.Output == String
}

所有这些编译都很好。但是,当我尝试实现工厂 API 时,出现编译错误:

public final class SessionFactory: SessionFactoryAPI { public func createStringFactory() -> T where T.Output == String { // 错误:无法将“StringSession”类型的值转换为预期的参数类型“T” 返回字符串会话() } }

有人对如何让它发挥作用有什么建议吗?

swift generics swift-protocols
1个回答
0
投票

错误:无法将“StringSession”类型的值转换为预期的参数类型“T”返回

意味着编译器不知道

T
应该是
SessionAPI
.

SessionFactoryAPI

public protocol SessionFactoryAPI {
  func createStringFactory<T: SessionAPI>() -> T where T.Output == String
}

你只是指定

T.Output
应该是什么(即
String

如果你真的需要约束

Output == String
,你可以尝试声明一个
StringSessionAPI
协议:

public protocol StringSessionAPI: SessionAPI where Output == String { }
public final class StringSession: StringSessionAPI {
    public typealias Output = String

    public let output: String
    public init(output: String) {
        self.output = output
    }
}

然后返回

any StringSessionAPI

public protocol SessionFactoryAPI {
    func createStringFactory() -> any StringSessionAPI
}

struct MyFactory: SessionFactoryAPI {
    func createStringFactory() -> any StringSessionAPI {
        StringSession(output: "output")
    }
}

let factory = MyFactory()
let stringSession: any StringSessionAPI = factory.createStringFactory()
print(stringSession.output) // prints "output"

或者您可以尝试使用关联类型而不是通用函数来使用:

public protocol SessionFactoryAPI {
    associatedtype T: SessionAPI where T.Output == String
    func createStringFactory() -> T
}

struct MyFactory: SessionFactoryAPI {
    func createStringFactory() -> StringSession {
        .init(output: "output")
    }
}

let factory = MyFactory()
let stringSession: StringSession = factory.createStringFactory()
print(stringSession.output) // prints "output"

© www.soinside.com 2019 - 2024. All rights reserved.