Reputation: 1455
I am trying to create a generalised class in Swift, Xcode 7.3 (so Swift 2.2), but I can not seem to get it past the compiler:
protocol Struct1Protocol {
}
struct Struct1 {
var name1: String
}
protocol Struct2Protocol {
}
struct Struct2: Struct2Protocol {
var name2: String
}
class StructDependent<T> {
func setupFrom<T:Struct1Protocol>(value: T) {
print("we want to setup StructDependent with struct 1")
}
func setupFrom<T:Struct2Protocol>(value: T) {
print("we want to setup StructDependent with struct 2")
}
}
class A<T> {
func test(value: T) {
let structInstance = StructDependent<T>()
// this gives a compiler error:
// Cannot invoke 'setupFrom' with an argument list of type '(T)'
structInstance.setupFrom(value)
}
}
The idea is to have a StructDependent
that can be set up from different structs. Class A should be able to call setupFrom if the class has been instantiated with a compatible struct. Like so:
let a = A<Struct1>()
let v = Struct1(name1: "")
a.test(v)
How would I go about this? I am a bit blocked here, so all ideas are welcome.
Upvotes: 1
Views: 116
Reputation: 534893
It seems to me that you're way over-thinking this. I would take a much more simple-minded view of the case and do it entirely without generics; instead, we just use a protocol as a kind of supertype of the two structs (just as we would use a superclass if the structs were classes):
protocol StructProtocol {
var name : String {get set}
func setup()
}
struct Struct1 : StructProtocol{
var name: String
func setup() {}
}
struct Struct2 : StructProtocol {
var name: String
func setup() {}
}
class StructDependent {
func setup(s:StructProtocol) {
s.setup() // or not, I don't care...
// or you could just switch on the type, e.g.:
switch s {
case is Struct1: // ...
case is Struct2: // ...
default: break
}
}
}
class A {
func test(value: StructProtocol) {
let structInstance = StructDependent()
structInstance.setup(value)
}
}
If StructDependent itself really needs to do different things depending on what setup
is called with, it can switch on the actual type. But it would be better the first way, where we just call something that both Struct1 and Struct2 know how to do, each in its own way.
Upvotes: 3
Reputation: 449
You need to put a type constraint on your generic type. You can use an all encompassing protocol for this constraint.
protocol StructProtocol {
}
protocol Struct1Protocol: StructProtocol {
}
struct Struct1: Struct1Protocol {
var name1: String
}
protocol Struct2Protocol: StructProtocol {
}
struct Struct2: Struct2Protocol {
var name2: String
}
class StructDependent<T> {
func setupFrom<T:Struct1Protocol>(value: T) {
print("we want to setup StructDependent with struct 1")
}
func setupFrom<T:Struct2Protocol>(value: T) {
print("we want to setup StructDependent with struct 2")
}
}
class A<T: Struct1Protocol> {
func test(value: T) {
let structInstance = StructDependent<T>()
// this gives a compiler error:
// Cannot invoke 'setupFrom' with an argument list of type '(T)'
structInstance.setupFrom(value)
}
}
let a = A<Struct1>()
Upvotes: 1