Home > OS >  swift Generics with protocol
swift Generics with protocol

Time:01-12

I created a function with generics

func sorted<T: MyProtocol>(array: [T]) -> [T] { ... }

and trying to call in

let array: [MyProtocol] = [...]
let sortedArray = sorted(array: array)

But getting the error

Type 'any MyProtocol' cannot conform to 'MyProtocol'

I understand that variable array is a box that can contain any kind of thing that conforms to the MyProtocol. But how I can resolve this problem ? I need to sorted any kind of MyProtocol

Tried something like this, but do not working

func sorted<T: any MyProtocol>(array: [T]) -> [T] { ... }

CodePudding user response:

I understand that variable array is a box that can contain any kind of thing that conforms to the MyProtocol.

That's exactly the problem with your code. When you wrote let array: [MyProtocol], rather than having an array of some concrete type that adopts the MyProtocol protocol, it is actually an array of an existential type that can store any objects that adopt the MyProtocol protocol, and such existential type does not adopt the protocol itself.

However, when you wrote the generic function func sorted<T: MyProtocol>, you specifically constrained the type T to be some type that adopts MyProtocol. Since the existential type itself does not adopt the protocol, you received the error.


To solve the problem, instead of constraining the function sorted, you can make the parameter itself and the return value an array of the existential type:

func sorted(array: [MyProtocol]) -> [MyProtocol]

Sidenote, starting from Swift 5.6, usages of existential types should be explicitly denoted, so your array declaration would become:

let array: [any MyProtocol] = [...]

And the function signature would become:

func sorted(array: [any MyProtocol]) -> [any MyProtocol]

CodePudding user response:

If you want to add a function to Array based on the Element you could do that by extending the array...

extension Array where Element: MyProtocol {
  func sorted() -> [Element] {
    // put your sorting logic here that uses the `MyProtocol` properties.
  }
}

Having said that though... if you can sort objects that conform to your MyProtocol. Then that protocol also will probably conform to Comparable.

And there is already a sorted function on [Comparable] (Array of objects conforming to Comparable). So you wouldn't need a new function for that.

To make that work you could define your protocol like...

protocol MyProtocol: Comparable {
}

This will then give your array the .sorted() function.

Documentation on Comparable... https://developer.apple.com/documentation/swift/comparable

CodePudding user response:

The error message is indicating that the type of the elements in the array variable, any MyProtocol, is not the same as the type specified in the sorted function's generic constraint, MyProtocol.

In Swift, any is a protocol that all types conform to. So any MyProtocol is a type that conforms to both the any and MyProtocol protocols.

To fix this error, you can either change the type of the array variable to [MyProtocol] or change the constraint of the sorted function to T: any MyProtocol.

  • Related