协议 associatedType 和 <>

Protocol associatedType and <>

在 swift 协议中使用 generic with function 或使用 associatedType 有什么区别?

protocol Repository {
    associatedtype T
    func add(data : T) -> Bool
}

protocol Repository {
    func add<T>(data : T) -> Bool
}
  • associatedtype 是 struct/class 中的静态类型,它通过 typealias 声明或类型推断采用协议。 class.

  • 的类型始终相同
  • 泛型可以是任何东西,甚至是同一个 class.

  • 中的不同类型

这个案例

protocol Repository {
    func add<T>(data : T) -> Bool
}

编译器理解为:"Any type that is fed to the func add will be acceptable and the result of the function will be Bool"

但是这个

protocol Repository {
    associatedtype T
    func add(data : T) -> Bool
}

被编译器理解为:“func add 将仅接受在 typealias T = ... 和 return Bool 中定义的类型”

在第二种情况下,您将泛型参数限制为类型别名类型。

当您在协议的多个函数中使用通用参数时,会出现另一个重要特征。在这种情况下,它保证 func add<T>func multiply<T> 将具有相同的类型 T。如果是通用函数,则不能保证。

protocol Calculable {
    associatedtype T
    func add<T>(a: T, b: T) -> T
    func multiply<T>(a: T, b: T) -> T
}
// In this case you know that T is the same for all functions

protocol CalculableDifferent {
    func add<T>(a: T, b: T) -> T
    func multiply<T>(a: T, b: T) -> T
}
// In this case add can accept One type, when multiply can accept Another

定义的关联类型使 classes 符合强类型协议。这提供编译时错误处理。

另一方面,泛型使得 class 符合协议的 es 更加灵活。

例如:

protocol AssociatedRepository {
    associatedtype T
    func add(data : T) -> Bool
}

protocol GenericRepository {
    func add<T>(data : T) -> Bool
}


class A: GenericRepository {
    func add<T>(data : T) -> Bool {
        return true
    }
}

class B: AssociatedRepository {
    typealias T = UIViewController
    func add(data : T) -> Bool {
        return true
    }
}

class A 可以将任何 class 放入 add(data:) 函数中,因此您需要确保该函数处理所有情况。

A().add(data: UIView())
A().add(data: UIViewController())

两者都有效

但是对于 class B,当您尝试放置除 UIViewController

之外的任何内容时,您将遇到编译时错误
B().add(data: UIView()) // compile-time error here
B().add(data: UIViewController())