Swift 带有关联类型的协议(类型查找不明确)
Swift protocol with associatedtype (ambiguous for type lookup)
我需要在协议中创建通用函数,在扩展中使用默认实现。它的功能应该与 item 一起工作,如 enum
:RawRepresentable
where RawValue == String
always。我试过了
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable // how this add restriction to RawValue == String
func test<T: SectionIdentifierEnum>(identifier: T) where T.RawValue == String
}
enum RequiresEnumDefault: String {
case `default`
}
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum.RawValue == String {
typealias SectionIdentifierEnum = RequiresEnumDefault
func test<T: SectionIdentifierEnum>(identifier: T) where T.RawValue == String {
print(T.rawValue)
}
}
但我有错误
- 'SectionIdentifierEnum' is ambiguous for type lookup in this context
- 'RawValue' is not a member type of 'T'
任何解决方案
通常,在协议上下文中涵盖泛型时,泛型类型持有者被视为可由协议的 associatedtype
表示。在您的示例中,这将是 SectionIdentifierEnum
,它充当受约束的 type 的占位符。但是,SectionIdenfierEnum
本身不是协议,因此不能将其用作泛型方法中的类型约束。但是,您 可以 将其用作 test(...)
方法中的类型。
Swift3.1
现在,目前 (Swift 3.1),您不能向 associatedtype
添加复杂的类型约束。但是,您可以提供仅适用于 Self
派生自 UIViewController
并通过将 SectionIdentifierEnum
类型设置为具体来实现 RequiresEnum
协议的情况的默认实现RequiresEnumDefault
类型。后者将确定关联的 RawValue
是此默认实现的 String
,因为具体 RequiresEnumDefault
类型的 RawValue
是 String
.
例如:
// Swift 3.1
// ---------
// Types that implement this protocol mustn't necessarily use a
// `SectionIdentifierEnum` type where `SectionIdentifierEnum.RawValue`
// is constrained to equal `String`.
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable
func test(identifier: SectionIdentifierEnum)
}
enum RequiresEnumDefault: String {
case `default`
}
// This extension, however, is only available for types that use
// `RequiresEnumDefault ` as the concrete type of `SectionIdentifierEnum`
// (in which case `SectionIdentifierEnum.RawValue` is `String`).
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum == RequiresEnumDefault {
func test(identifier: SectionIdentifierEnum) {
print(identifier.rawValue)
}
}
// Example usage.
class MyViewController : UIViewController, RequiresEnum {
typealias SectionIdentifierEnum = RequiresEnumDefault
// ...
}
let foo = MyViewController()
foo.test(identifier: RequiresEnumDefault.default)
// prints "default" (using extension:s default implementation)
以上,test(...)
的默认实现仅在 SectionIdentifierEnum
等于具体类型 RequireEnumDefault
时可用(并且 Self
派生自 UIViewController
.. .).相反,如果您希望它仅在 SectionIdentifierEnum
是 任何 String
类型为 RawValue
的枚举时可用,您可以相应地修改扩展的类型约束:
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable
func test(identifier: SectionIdentifierEnum)
}
enum RequiresEnumDefault: String {
case `default`
}
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum.RawValue == String {
func test(identifier: SectionIdentifierEnum) {
print(identifier.rawValue)
}
}
// Example usage.
enum EnumWithStringRawValue: String {
case foo
}
class MyViewController : UIViewController, RequiresEnum {
typealias SectionIdentifierEnum = EnumWithStringRawValue
// ...
}
let foo = MyViewController()
foo.test(identifier: EnumWithStringRawValue.foo)
// prints "foo" (using extension:s default implementation)
一旦 Swift 4 发布,您将能够向 associatedtype
:s 添加更复杂的约束,根据 Swift 进化提案的实施:
这样的话上面可以修改成:
// Swift 4
// -------
// Here, all types that implement this protocol must use a
// `SectionIdentifierEnum` type where `SectionIdentifierEnum.RawValue`
// is equal to `String`.
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable
where SectionIdentifierEnum.RawValue == String
func test(identifier: SectionIdentifierEnum)
}
enum RequiresEnumDefault: String {
case `default`
}
// For the specific case where `SectionIdentifierEnum` equals
// `RequiresEnumDefault` (and where `Self` derives from `UIViewController`),
// this default implementation is readily available.
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum == RequiresEnumDefault {
func test(identifier: SectionIdentifierEnum) {
print(identifier.rawValue)
}
}
// Example usage.
class MyViewController : UIViewController, RequiresEnum {
typealias SectionIdentifierEnum = RequiresEnumDefault
// ...
}
let foo = MyViewController()
foo.test(identifier: RequiresEnumDefault.default)
// prints "default" (using extension:s default implementation)
同样修改对 test(...)
默认实现的约束,不仅针对 SectionIdentifierEnum
等于 RequiresEnumDefault
的情况(而且针对任何枚举:在这种情况下我们知道这样的枚举将由于协议定义中对 associatedtype
的限制,总是有 RawValue
String
。
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable
where SectionIdentifierEnum.RawValue == String
func test(identifier: SectionIdentifierEnum)
}
enum RequiresEnumDefault: String {
case `default`
}
// From the constraint on the `RawValue` of `SectionIdentifierEnum`
// above, we know that `RawValue` equals `String`.
extension RequiresEnum where Self: UIViewController {
func test(identifier: SectionIdentifierEnum) {
print(identifier.rawValue)
}
}
// Example usage.
enum EnumWithStringRawValue: String {
case foo
}
class MyViewController : UIViewController, RequiresEnum {
typealias SectionIdentifierEnum = EnumWithStringRawValue
// ...
}
let foo = MyViewController()
foo.test(identifier: EnumWithStringRawValue.foo)
// prints "foo" (using extension:s default implementation)
我需要在协议中创建通用函数,在扩展中使用默认实现。它的功能应该与 item 一起工作,如 enum
:RawRepresentable
where RawValue == String
always。我试过了
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable // how this add restriction to RawValue == String
func test<T: SectionIdentifierEnum>(identifier: T) where T.RawValue == String
}
enum RequiresEnumDefault: String {
case `default`
}
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum.RawValue == String {
typealias SectionIdentifierEnum = RequiresEnumDefault
func test<T: SectionIdentifierEnum>(identifier: T) where T.RawValue == String {
print(T.rawValue)
}
}
但我有错误
- 'SectionIdentifierEnum' is ambiguous for type lookup in this context
- 'RawValue' is not a member type of 'T'
任何解决方案
通常,在协议上下文中涵盖泛型时,泛型类型持有者被视为可由协议的 associatedtype
表示。在您的示例中,这将是 SectionIdentifierEnum
,它充当受约束的 type 的占位符。但是,SectionIdenfierEnum
本身不是协议,因此不能将其用作泛型方法中的类型约束。但是,您 可以 将其用作 test(...)
方法中的类型。
Swift3.1
现在,目前 (Swift 3.1),您不能向 associatedtype
添加复杂的类型约束。但是,您可以提供仅适用于 Self
派生自 UIViewController
并通过将 SectionIdentifierEnum
类型设置为具体来实现 RequiresEnum
协议的情况的默认实现RequiresEnumDefault
类型。后者将确定关联的 RawValue
是此默认实现的 String
,因为具体 RequiresEnumDefault
类型的 RawValue
是 String
.
例如:
// Swift 3.1
// ---------
// Types that implement this protocol mustn't necessarily use a
// `SectionIdentifierEnum` type where `SectionIdentifierEnum.RawValue`
// is constrained to equal `String`.
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable
func test(identifier: SectionIdentifierEnum)
}
enum RequiresEnumDefault: String {
case `default`
}
// This extension, however, is only available for types that use
// `RequiresEnumDefault ` as the concrete type of `SectionIdentifierEnum`
// (in which case `SectionIdentifierEnum.RawValue` is `String`).
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum == RequiresEnumDefault {
func test(identifier: SectionIdentifierEnum) {
print(identifier.rawValue)
}
}
// Example usage.
class MyViewController : UIViewController, RequiresEnum {
typealias SectionIdentifierEnum = RequiresEnumDefault
// ...
}
let foo = MyViewController()
foo.test(identifier: RequiresEnumDefault.default)
// prints "default" (using extension:s default implementation)
以上,test(...)
的默认实现仅在 SectionIdentifierEnum
等于具体类型 RequireEnumDefault
时可用(并且 Self
派生自 UIViewController
.. .).相反,如果您希望它仅在 SectionIdentifierEnum
是 任何 String
类型为 RawValue
的枚举时可用,您可以相应地修改扩展的类型约束:
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable
func test(identifier: SectionIdentifierEnum)
}
enum RequiresEnumDefault: String {
case `default`
}
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum.RawValue == String {
func test(identifier: SectionIdentifierEnum) {
print(identifier.rawValue)
}
}
// Example usage.
enum EnumWithStringRawValue: String {
case foo
}
class MyViewController : UIViewController, RequiresEnum {
typealias SectionIdentifierEnum = EnumWithStringRawValue
// ...
}
let foo = MyViewController()
foo.test(identifier: EnumWithStringRawValue.foo)
// prints "foo" (using extension:s default implementation)
一旦 Swift 4 发布,您将能够向 associatedtype
:s 添加更复杂的约束,根据 Swift 进化提案的实施:
这样的话上面可以修改成:
// Swift 4
// -------
// Here, all types that implement this protocol must use a
// `SectionIdentifierEnum` type where `SectionIdentifierEnum.RawValue`
// is equal to `String`.
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable
where SectionIdentifierEnum.RawValue == String
func test(identifier: SectionIdentifierEnum)
}
enum RequiresEnumDefault: String {
case `default`
}
// For the specific case where `SectionIdentifierEnum` equals
// `RequiresEnumDefault` (and where `Self` derives from `UIViewController`),
// this default implementation is readily available.
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum == RequiresEnumDefault {
func test(identifier: SectionIdentifierEnum) {
print(identifier.rawValue)
}
}
// Example usage.
class MyViewController : UIViewController, RequiresEnum {
typealias SectionIdentifierEnum = RequiresEnumDefault
// ...
}
let foo = MyViewController()
foo.test(identifier: RequiresEnumDefault.default)
// prints "default" (using extension:s default implementation)
同样修改对 test(...)
默认实现的约束,不仅针对 SectionIdentifierEnum
等于 RequiresEnumDefault
的情况(而且针对任何枚举:在这种情况下我们知道这样的枚举将由于协议定义中对 associatedtype
的限制,总是有 RawValue
String
。
protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable
where SectionIdentifierEnum.RawValue == String
func test(identifier: SectionIdentifierEnum)
}
enum RequiresEnumDefault: String {
case `default`
}
// From the constraint on the `RawValue` of `SectionIdentifierEnum`
// above, we know that `RawValue` equals `String`.
extension RequiresEnum where Self: UIViewController {
func test(identifier: SectionIdentifierEnum) {
print(identifier.rawValue)
}
}
// Example usage.
enum EnumWithStringRawValue: String {
case foo
}
class MyViewController : UIViewController, RequiresEnum {
typealias SectionIdentifierEnum = EnumWithStringRawValue
// ...
}
let foo = MyViewController()
foo.test(identifier: EnumWithStringRawValue.foo)
// prints "foo" (using extension:s default implementation)