Swift protocol with associated type (type lookup is not clear)

I need to create a generic function in the protocol and use the default implementation in the extension. It should use item as an enumeration: RawRepresentable, where RawValue == String always. I tried

protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable // how this add restriction to RawValue == String

func test(identifier: T) where T.RawValue == String
}

enum RequiresEnumDefault: String {
case `default`
}< br />
extension RequiresEnum where Self: UIViewController, SectionIdentifierEnum.RawValue == String {

typealias SectionIdentifierEnum = RequiresEnumDefault

func test(identifier : T) where T.RawValue == String {
print(T.rawValue)
}

}

But I have an error

  • ‘SectionIdentifierEnum’ is ambiguous for type lookup in this context
  • ‘RawValue’ is not a member type of’T’

any Solution

Generally, when the generic type is overridden in the context of the protocol, the generic type holder Is considered to be represented by the related type of the protocol. In your example, this would be SectionIdentifierEnum, which acts as a placeholder for the constrained type. However, SectionIdenfierEnum itself is not a protocol, so it cannot be used as a generic method in Type constraints. However, you can use it as the type itself in the test(…) method.

Swift 3.1

Now, currently (Swift 3.1), you cannot Add complex type constraints to the associated type. However, you can provide a default implementation that only applies to the case where Self is derived from UIViewController and implement the RequiresEnum protocol by setting the SectionIdentifierEnum type to the specific RequiresEnumDefault type. The latter will determine the association The RawValue is the String implemented by this default, because the RawValue of the specific RequiresEnumDefault type is String.

For example.:

// 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)
}
< br />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
// ...
}< br />
let foo = MyViewController()
foo.test(identifier: RequiresEnumDefault.default)
// prints "default" (using extension:s default implementation)

< p>Above, the default implementation of test(…) is only available when SectionIdentifierEnum is equal to the concrete type RequireEnumDefault (and Self is derived from UIViewController…). If you want it to be available only when SectionIdentifierEnum is any enumeration with String type RawValue, then corresponding Modify the extension type constraints:

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 will be able to The implementation of the Swift evolution proposal adds more complex constraints to the associated types:

> SE-0142: Permit where clauses to constrain associated types

p>

In this case, the above content can be modified as follows:

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

Also modify test(… The constraints of the default implementation of) are not only for the case where SectionIdentifierEnum is equal to RequiresEnumDefault (but for any enumeration: in this case, we know that such an enumeration will always have a RawValue string because of the associatedtype in the protocol definition) .

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

I need to create a generic function in the protocol and use the default implementation in the extension. It should use item as an enumeration: RawRepresentable, where RawValue == String always. I tried

protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable // how this add restriction to RawValue == String

func test(identifier: T) where T.RawValue == String
}

enum RequiresEnumDefault: String {
case `default`
}

extensi on RequiresEnum where Self: UIViewController, SectionIdentifierEnum.RawValue == String {

typealias SectionIdentifierEnum = RequiresEnumDefault

func test(identifier: T) where T.RawValue == String {
print(T.rawValue)
}

}

But I have an error

  • ‘SectionIdentifierEnum’ is ambiguous for type lookup in this context
  • ‘RawValue’ is not a member type of’T’

Any solution

Usually, when the generic type is overridden in the context of the protocol, the holder of the generic type is considered to be relevant to the protocol Type representation. In your example, this would be SectionIdentifierEnum, which acts as a placeholder for the constrained type. However, SectionIdenfierEnum itself is not a protocol, so it cannot be used as a type constraint in a generic method. However, you can Use it as the type itself in the test(…) method.

Swift 3.1

Now, currently (Swift 3.1), you cannot add complex type constraints to Association type. However, you can provide a default implementation that only applies to the case where Self derives from UIViewController and implements the RequiresEnum protocol by setting the SectionIdentifierEnum type to a specific RequiresEnumDefault type. The latter will determine that the associated RawValue is implemented by this default String, because the RawValue of the specific RequiresEnumDefault type is String.

For example.:

// 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 {
typeali as 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 is equal to the concrete type RequireEnumDefault (and Self is derived from UIViewController…). If you Hope it is only available when SectionIdentifierEnum is any enumeration with String type RawValue, then modify the extended type constraint accordingly:

protocol RequiresEnum: class {
associatedtype SectionIdentifierEnum: RawRepresentable

func test(identifier: SectionIdentifierEnum)
}

enum RequiresEnumDefault: String {
case `default`
}< br />
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()< br />foo.test(identifier: EnumWithStringRawValue.foo)
// prints "foo" (using extension:s default implementation)

Once Swift 4 is released, you will be able to follow the Swift evolution proposal The implementation of adding more complex constraints to the associated types:

> SE-0142: Permit where clauses to constrain associated types

In this case, the above content can be modified to:< /p>

// 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`
}
< br />// For the specific case where `SectionIdentifierEnum` equals
// `RequiresEnumDefault` (and where `Self` derives from `UIViewController`),
// this default implementation is readily available.< br />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)

Also modify the constraints on the default implementation of test(…), not only for the case where SectionIdentifierEnum is equal to RequiresEnumDefault (but for any enumeration: in this case, we know that such an enumeration will always have RawValue characters String, because of the associatedtype in the protocol definition).

protocol RequiresEnum: class {
associatedt ype 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)
}
}< br />
// 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)

Leave a Comment

Your email address will not be published.