简体   繁体   English

具有关联类型的Swift协议(类型查找不明确)

[英]Swift protocol with associatedtype (ambiguous for type lookup)

I need to create generic function in protocol with default implementation in extension. 我需要在协议中创建泛型函数,并在扩展中使用默认实现。 It func should work with item as enum : RawRepresentable where RawValue == String always. 它应该使用item作为enumRawRepresentable ,其中RawValue == String always。 I tried 我试过了

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)
    }

}

but i have errors 但我有错误

  • 'SectionIdentifierEnum' is ambiguous for type lookup in this context 对于此上下文中的类型查找,“SectionIdentifierEnum”不明确
  • 'RawValue' is not a member type of 'T' 'RawValue'不是'T'的成员类型

Any solutions 任何解决方案

Generally when covering generics in the context of protocols, the generic typeholder is seen as representable by an associatedtype of the protocol. 通常,当在协议的上下文中覆盖泛型时,通用类型持有者被视为可由协议的associatedtype表示。 In your example this would be SectionIdentifierEnum , which acts as a placeholder for a constrained type . 在您的示例中,这将是SectionIdentifierEnum ,它充当受约束类型的占位符。 SectionIdenfierEnum is not, however, a protocol by itself, so cannot use it as a type constraint in a generic method. 但是, SectionIdenfierEnum本身不是一个协议,因此不能将它用作泛型方法中的类型约束。 You can , however, use it as the type itself in your test(...) method. 但是,您可以test(...)方法中将其用作类型本身。


Swift 3.1 Swift 3.1

Now, currently (Swift 3.1), you can't add sophisticated type constrains to an associatedtype . 现在,当前(Swift 3.1),您无法将复杂的类型约束添加到associatedtype类型。 You could can, however, supply a default implementation available only for the case the where Self derives from UIViewController and implements the RequiresEnum protocol by setting the SectionIdentifierEnum type to the concrete RequiresEnumDefault type. 但是,您可以提供一个默认实现,仅适用于SelfUIViewController派生的情况,并通过将SectionIdentifierEnum类型设置为具体的RequiresEnumDefault类型来实现RequiresEnum协议。 The latter will ascertain that the associated RawValue is String for this default implementation, as the RawValue of the concrete RequiresEnumDefault type is String . 后者将确定关联的RawValue是此默认实现的String ,因为具体RequiresEnumDefault类型的RawValueString

Eg: 例如:

// 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)

Above, the default implementation of test(...) is only available when SectionIdentifierEnum equals the concrete type RequireEnumDefault (and Self derives from UIViewController ...). 上面, test(...)的默认实现仅在SectionIdentifierEnum等于具体类型RequireEnumDefault (和Self派生自UIViewController ...)时可用。 If instead you want it to only be available when SectionIdentifierEnum is any enum with String typed RawValue , you modify the type constraint of the extensions accordingly: 如果您希望它仅在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)

Once Swift 4 is released, you'll be able to add more sophisticated constraints to associatedtype :s, as per the implementation of Swift evolution proposal: 一旦Swift 4发布,您将能够根据Swift evolution提案的实现向associatedtype添加更复杂的约束:

In which case the above can be modified into: 在这种情况下,上述内容可以修改为:

// 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)

Likewise modifying the constraint on the default implementation of test(...) not only to the case where SectionIdentifierEnum equals RequiresEnumDefault (but to any enum: in this case we know such enum will always have a RawValue String , due to the constraint on the associatedtype in the protocol definition). 同样修改对test(...)的默认实现的约束,不仅仅是对于SectionIdentifierEnum等于RequiresEnumDefault的情况(但对于任何枚举:在这种情况下,我们知道这样的枚举将始终具有RawValue String ,因为对协议定义中的associatedtype )。

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM