This protocol is just invented by me to make sense of generics an associated types. Not sure how to write a class/struct that conforms to it. Thanks!
protocol MyProto<T> {
associatedtype T: Sequence<Int>
func myFunc(a: T)
}
This protocol is just invented by me to make sense of generics an associated types. Not sure how to write a class/struct that conforms to it. Thanks!
protocol MyProto<T> {
associatedtype T: Sequence<Int>
func myFunc(a: T)
}
Here are a few ways to make a type conform to MyProto
.
You can conform by picking a specific type for T
that satisfies the constraint. (The constraint is that T
must conform to Sequence
and its Element
must be Int
.) Then write an implementation of myFunc
that takes an argument of that specific type. Example:
struct MyStruct: MyProto {
// Set conforms to Sequence.
typealias T = Set<Int>
func myFunc(a: Set<Int>) {
print("\(a.count)")
}
}
You can also make an existing type conform this way, using an extension on the existing type. For example:
extension String: MyProto {
// Range conforms to Sequence.
typealias T = Range<Int>
func myFunc(a: Range<Int>) {
print("\(self) \(a)")
}
}
Another way to conform is to create a generic type, and then make the generic type conform only when its generic parameter satisfies the constraint. Example:
struct MyGenericStruct<T> { }
extension MyGenericStruct: MyProto where T: Sequence<Int> {
func myFunc(a: T) {
print("\(a)")
}
}
This is called a conditional conformance, because MyGenericStruct
only conforms to MyProto
if its T
parameter satisfies the constraint.
If your type always constrains T
, it can conform unconditionally, like this:
struct MyLessGenericStruct<T: Sequence<Int>> { }
// T always satisfies the MyProto constraint, so this
// conformance is unconditional.
extension MyLessGenericStruct: MyProto {
func myFunc(a: T) {
print(a)
}
}
You can also make an existing generic type conform to MyProto
. Usually this will be a conditional conformance. Example:
extension Array: MyProto where Element: Sequence, Element.Element == Int {
typealias T = Element
func myFunc(a: T) {
let found = self.contains { $0.elementsEqual(a) }
print(found)
}
}
You can also conform if you have a generic parameter that conforms, by using your parameter's conformance to implement your own conformance.
extension Set: MyProto where Element: MyProto {
typealias T = Element.T
func myFunc(a: T) {
self.first?.myFunc(a: a)
}
}
Please note that in many of these examples, I have explicitly defined T
using a typealias
. But often Swift can infer T
from the type of a property or function. For example, we could write that last example like this instead:
extension Set: MyProto where Element: MyProto {
func myFunc(a: Element.T) {
self.first?.myFunc(a: a)
}
}
Swift sees that myFunc
can satisfy the MyProto
requirement if T
is Element.T
, and doesn't find any contradictory declarations, so it infers T = Element.T
.