Reputation: 764
struct Lock<Element: Hashable> {
var element: Element
init(_ element: Element, _ args:[Lock<Element>]? = nil) {
self.element = element
}
}
Is it possible to modify this kind of struct to be able call init() with different Element
types in arguments?
Lock("element", [Lock("100")])
it's ok
Lock("element", [Lock(100)])
this causes an error: Cannot convert value of type 'Int' to expected argument type 'Lock<_>'
Upvotes: 4
Views: 417
Reputation: 7341
You have 2 options for doing this.
The simple solution, improving on @Cristik's answer, is to have another initialiser that doesn't expect another generic parameter:
struct Lock<Element> {
var element: Element
init(_ element: Element) {
self.element = element
}
init<T>(_ element: Element, _ args: [Lock<T>]?) {
self.init(element)
}
}
You can then have the code you want above, but you lose the information that Element
conforms to Hashable
.
Your second option is to create a protocol
using an associatedtype
. Using a similar trick with having 2 init
s, you can do the same except explicitly defining the types:
protocol Lock {
associatedtype Element
init(_ element: Element)
init<T>(_ element: Element, _ args: [T]?) where T: Lock
}
struct HashableLock<H: Hashable>: Lock {
typealias Element = H
var element: Element
init(_ element: Element) {
self.element = element
}
init<T>(_ element: Element, _ args: [T]?) where T: Lock {
self.init(element)
}
}
struct IntLock: Lock {
typealias Element = Int
var element: Int
init(_ element: Int) {
self.element = element
}
init<T>(_ element: Int, _ args: [T]?) where T: Lock {
self.init(element)
}
}
Then you can create locks like this:
let stringStringLock = HashableLock("element", [HashableLock("100")])
let stringIntLock = HashableLock("element", [IntLock(100)])
The first version is a lot cleaner but it's more limiting. It's up to you which one to use, depends on your needs.
Upvotes: 1
Reputation: 32825
You might get better results by making the initializer generic:
struct Lock<Element: Hashable> {
var element: Element
init<T>(_ element: Element, _ args:[Lock<T>]? = nil) {
self.element = element
}
}
Upvotes: 0
Reputation: 3945
This cannot be done.
The reason is that Element
gets assigned to the type used for the element parameter in init
. Now that same type has to be used whenever Element
appears in the struct but if you want the generic type of Lock
to be anything else, you'll need to declare another generic type.
The problem here is that by adding another generic type to Lock
(i.e. Lock<Element, AnotherElement>
) is that now the Lock
in your init
will need to specify two generic types, and so on.
Upvotes: 0