【问题标题】:Implement generic protocol method with but use generic for whole class实现泛型协议方法,但对整个类使用泛型
【发布时间】:2020-03-15 19:02:28
【问题描述】:

我正在尝试实现一个具有泛型参数的协议方法,然后在我的整个类中使用泛型类型,而不是仅仅在方法上使用,就像这样

protocol FirstProtocol {
}

protocol SecondProtocol {
    func foo<T: FirstProtocol>(argument: T)
}

class MyType<T: FirstProtocol>: SecondProtocol {
    var value: T? = nil
    func foo<T>(argument: T) {
        value = argument     // ERROR: Cannot assign value of type 'T' to type 'T?'
    }
}

所以 swift 编译器接受 foo&lt;T&gt;(argument:T) 匹配 SecondProtocol 的方法,如果我注释掉错误行它编译得很好,但它不会让我将 argument 分配给 value 即使 valueargument 应该是相同的类型,编译器也会抱怨它们是不同的类型。

【问题讨论】:

  • 我试过value = T?.some(argument),它给了我Cannot assign value of type 'Optional&lt;T&gt;' to type 'T?' 错误。

标签: swift generics swift-protocols swift5


【解决方案1】:

argumentvalue 的类型确实是不同的类型。 foo 中的 T 泛型参数只是一个标识符,我可以将其更改为其他任何内容:

class MyType<T: FirstProtocol>: SecondProtocol {
    var value: T? = nil
    func foo<AnythingElse>(argument: AnythingElse) {
        // MyType still conforms to SecondProtocol
    }
}

foo 中的T 是一个全新的通用参数,不同于MyType 中的T。他们只是碰巧有相同的名字。

请注意,当您声明一个泛型方法时,是 调用者 决定泛型类型是什么,而不是泛型方法。 foo 在这里想说的是“我希望foo 中的TMyType 中的T 类型相同”,但它不能说它自己的泛型参数!

修复它的一种方法是使SecondProtocol 具有关联的类型:

protocol SecondProtocol {
    // name this properly!
    associatedtype SomeType: FirstProtocol
    func foo(argument: SomeType)
}

class MyType<T: FirstProtocol>: SecondProtocol {
    typealias SomeType = T // here is where it says "I want 'SomeType' to be the same type as 'T'!"
    var value: T? = nil
    func foo(argument: T) {
        value = argument
    }
}

【讨论】:

  • 好的,这在我给你的简单示例中有效,问题是我只能用作 SecondProtocol 通用约束,这会破坏其他人在我正在处理的项目中使用它的方式。我真的想做类似 foo(argument: T1) where T1 == T 的事情,但是编译器然后抱怨“相同类型的要求使泛型参数'T1'和'T'等效”,但这就是我想要的.
  • 因为我想做的只是单元测试,所以我发现了一个涉及强制转换的稍微笨拙的解决方案。
【解决方案2】:

即使值和参数应该是相同的类型,它也不会让我将参数分配给值,编译器会抱怨它们好像是不同的类型。

想想这个案例:

A 类:FirstProtocol { }

B 类:FirstProtocol { }

A 类和 B 类是 func foo(argument: T){} 可接受的泛型类型,但您可以将 A 类的实例分配给 B 类吗?

class MyType<T: FirstProtocol>: SecondProtocol

去掉“:FirstProtocol”应该可以,或者用基类代替FirstProtocol

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-19
    • 2022-01-21
    • 1970-01-01
    • 2018-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多