协议 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())
在 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())