What is an appropriate way to solve the following example with swift?
I know because of type erasure that you cannot assign StructB
to item2
in the constructor. In other languages like Java I would solve the problem by not having a generic class parameter T
in the Container
struct but let vars item
and item2
just be the type of ProtocolA
(like var item2: ProtocolA
).
This is not allowed by swift: Protocol ‘ProtocolA’ can only be used as a generic constraint because it has Self or associated type requirements
I worked through this section of swifts documentation about generics but so far I was not able to adapt a solution for my simple problem:
protocol ProtocolA {
associatedtype B
func foo() -> B
}
struct StructA: ProtocolA {
typealias B = String
func foo() -> String {
"Hello"
}
}
struct StructB: ProtocolA {
typealias B = Double
func foo() -> Double {
0.0
}
}
struct Container<T: ProtocolA> {
var item: T
var item2: T
init(item: T) {
self.item = item
self.item2 = StructB() // err: Cannot assign value of type 'StructB' to type 'T'
}
}
I also want to know how a solution could look if I do not want to specify a generic type parameter at all for the container struct. So that I could write the following:
func test() {
let container = Container(StructA()) // no type given
}
2
Answers
The only way to do something like you want is :
For the problem as described, the answer is very straightforward:
I get the feeling that there’s something deeper to this question, which is why Alexander was asking for more context. As written, the question’s answer seems too simple, so some of us assume that there’s more that you didn’t explain, and we want to avoid a round of "here’s the answer" followed by "that’s not what I meant."
As you wrote it, you try to force
item
anditem2
to have the same type. That’s obviously not what you mean becauseT
is given by the caller, anditem2
is always StructB (which does not have to equalT
, as the error explains).Is there another way you intend to call this code? It’s unclear what code that calls
foo()
would look like. Do you have some other way you intend to initialize Container that you didn’t explain in your question?Maybe you want two different types, and you just want StructB to be the default? In that case, it would look like (based on Ptit Xav’s answer):
The
where U == StructB
allows you to make a default type for U.