Swift 无法使用匹配的类型转换类型的值-我是否已达到编译器限制?

Swift 无法使用匹配的类型转换类型的值-我是否已达到编译器限制?,swift,compiler-errors,swift-protocols,Swift,Compiler Errors,Swift Protocols,背景: 我正在构建一个带有服务层的应用程序,它应该返回相似的模型(例如,所有模型都有一个text:String属性,在协议TextModel中定义)。该服务拥有一个存储库,用于查找并返回符合TextModel的具体类型的模型。存储库需要保留内部工作的具体类型信息。我想让服务不受模型的具体类型的影响,这样我就不必对每个模型类型重复它。编译器不允许我这么做 问题: 我在操场上简化的以下代码将不会编译: enum Result<T> { case success(T) c

背景:

我正在构建一个带有服务层的应用程序,它应该返回相似的模型(例如,所有模型都有一个
text:String
属性,在协议
TextModel
中定义)。该服务拥有一个存储库,用于查找并返回符合
TextModel
的具体类型的模型。存储库需要保留内部工作的具体类型信息。我想让服务不受模型的具体类型的影响,这样我就不必对每个模型类型重复它。编译器不允许我这么做

问题:

我在操场上简化的以下代码将不会编译:

enum Result<T> {

    case success(T)
    case error
}

// Model Layer

protocol TextModel {

    var text: String { get }
}

struct Person: TextModel {

    let text: String
}

// Service Layer

class TextModelService {

    let repository: TextModelRepositoryType

    init(repository: TextModelRepositoryType) {

        self.repository = repository
    }

    func find(completion: @escaping (Result<TextModel>) -> ()) {

        repository.find(completion: completion)
    }
}

// Repository Layer

protocol TextModelRepositoryType {

    func find(completion: @escaping (Result<TextModel>) -> ())
}

protocol PersonRepositoryType {

    func findPerson(completion: @escaping (Result<Person>) -> ())
}

class PersonRepository: PersonRepositoryType, TextModelRepositoryType {

    func find(completion: @escaping (Result<TextModel>) -> ()) {

        // ERROR HERE: "Cannot convert value of type '(Result<TextModel>) -> ()' to expected argument type '(Result<Person>) -> ()'"
        findPerson(completion: completion)
    }

    func findPerson(completion: @escaping (Result<Person>) -> ()) {

        let person = Person(text: "Adam")
        completion(.success(person))
    }
}

let repository = PersonRepository()
let service = TextModelService(repository: repository)
service.find { result in

    // result should be a Result<Person>
}
枚举结果{
成功案例(T)
案例错误
}
//模型层
协议文本模型{
变量文本:字符串{get}
}
结构人:TextModel{
让文本:字符串
}
//服务层
类TextModelService{
let存储库:TextModelRepositoryType
init(存储库:TextModelRepositoryType){
self.repository=存储库
}
func find(完成:@escaping(Result)->()){
查找(完成:完成)
}
}
//存储库层
协议TextModelRepositoryType{
func find(完成:@escaping(Result)->())
}
协议PersonRepositoryType{
func findPerson(完成:@escaping(Result)->())
}
类PersonRepository:PersonRepositoryType、TextModelRepositoryType{
func find(完成:@escaping(Result)->()){
//此处出现错误:“无法将类型为“(结果)->()”的值转换为预期的参数类型“(结果)->()”
findPerson(完成:完成)
}
func findPerson(完成:@escaping(Result)->()){
让人=人(文本:“亚当”)
完成(.success(个人))
}
}
let repository=PersonRepository()
let service=TextModelService(存储库:repository)
service.find{结果在
//结果应该是结果
}
我不明白为什么当
Person
明确符合
TextModel
时,编译器声明它
无法将类型为“(结果)->()”的值转换为预期的参数类型“(结果)->()”

同样有趣的是,当我删除
结果
类型并在完成时传递一个未包装的类型(例如
(TextModel?)->()
)时,编译器不会感到不安


我是否在Swift编译器中遇到了限制?还是我遗漏了什么

因为Swift具有不变的泛型类型,
T
无法转换为
T
,即使
A
可以转换为
B

这种情况下的一个解决方法是自己创建转换方法:

enum Result<T> {

    case success(T)
    case error

    func cast<R>() -> Result<R>? {
        switch self {
        case .error: return .error
        case .success(let t) where t is R: return .success(t as! R)
        default: return nil
        }
    }
}

extension Result where T : TextModel {
    func convertToTextModel() -> Result<TextModel> {
        switch self {
        case .error: return .error
        case .success(let t): return .success(t)
        }
    }
}
在呼叫端:

let repository = PersonRepository()
let service = TextModelService(repository: repository)
service.find { result in
    if let person: Result<Person> = result.cast() {
        // ...
    }
}
let repository=PersonRepository()
let service=TextModelService(存储库:repository)
service.find{结果在
如果让人:Result=Result.cast(){
// ...
}
}

是否必须使用
结果
Result
也能正常工作吗?对“swift类型差异”进行了一些搜索。斯威夫特的泛型是不变性的,也就是说,是的,这就是它的行为。斯威普,我从问题中去掉了可选性。感谢瑞奇,我忽略了结果将泛型添加到等式中的事实。谢谢你的引导。我会做些调查的。非常感谢。这是一种享受。我认为我在这里真正学到的是,我过度设计了系统,支持可测试性!再次感谢。
let repository = PersonRepository()
let service = TextModelService(repository: repository)
service.find { result in
    if let person: Result<Person> = result.cast() {
        // ...
    }
}