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

时间:2017-07-27 16:45:55

标签: swift generics protocols swift-protocols associated-types

我需要在协议中创建泛型函数,并在扩展中使用默认实现。它的func应该与enum RawRepresentable项一起使用RawValue == String。我试过了

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

}

但我有错误

  
      
  • &#39; SectionIdentifierEnum&#39;在这种情况下对类型查找不明确
  •   
  • &#39; RawValue&#39;不是&#39; <&#39;
  • 的会员类型   

任何解决方案

1 个答案:

答案 0 :(得分:5)

通常在协议上下文中覆盖泛型时,泛型类型持有者被视为associatedtype协议可表示。在您的示例中,这将是SectionIdentifierEnum,它充当受约束的类型的占位符。但是,SectionIdenfierEnum本身不是协议,因此不能将其用作泛型方法中的类型约束。但 可以在test(...)方法中将其用作类型本身。

Swift 3.1

现在,目前(Swift 3.1),您无法向associatedtype添加复杂的类型约束。但是,您可以提供默认实现,仅适用于SelfUIViewController派生的情况,并通过将RequiresEnum类型设置为具体来实现SectionIdentifierEnum协议RequiresEnumDefault类型。后者将确定此默认实现的关联RawValueString,因为具体RawValue类型的RequiresEnumDefaultString

E.g:

// 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 <{1}} 的情况下才能使用它,则相应地修改扩展的类型约束:

RawValue

一旦发布了Swift 4,您就可以根据Swift演化提案的实现向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) :s添加更复杂的约束:

在这种情况下,上述内容可以修改为:

associatedtype

同样修改// 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的约束,RawValue String

associatedtype