Reputation: 13012
Ok, I'll try to explain you what I'm trying to get with a minimum viable example: I'd like to have a struct like this:
struct MyStruct {
let aBool: Bool
let aInt: Int
let aHashable: Hashable?
}
but of course this can't be done because:
Protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
and this is fine. I can get what I want this way:
struct MyStruct<T> where T: Hashable {
let aBool: Bool
let aInt: Int
let aHashable: T?
}
But I want my struct to have two init this way:
struct MyStruct<T> where T: Hashable {
let aBool: Bool
let aInt: Int
let aHashable: T?
init(aBool: Bool, aInt: Int) {
self.init(aBool: aBool, aInt: aInt, aHashable: nil)
}
init(aHashable: T?) {
self.init(aBool: false, aInt: 0, aHashable: aHashable)
}
private init(aBool: Bool, aInt: Int, aHashable: T?) {
self.aBool = aBool
self.aInt = aInt
self.aHashable = aHashable
}
}
And if I try to init the struct like this:
let myStruct = MyStruct(aBool: true, aInt: 10)
I get an error:
Generic parameter 'T' could not be inferred
The problem is that even if I turn the struct into a non generic struct (with a couple of generic init):
struct MyStruct {
let aBool: Bool
let aInt: Int
let aHashable: T?
init(aBool: Bool, aInt: Int) {
self.init(aBool: aBool, aInt: aInt, aHashable: nil)
}
init<T>(aHashable: T?) where T: Hashable {
self.init(aBool: false, aInt: 0, aHashable: aHashable)
}
private init<T>(aBool: Bool, aInt: Int, aHashable: T?) where T: Hashable {
self.aBool = aBool
self.aInt = aInt
self.aHashable = aHashable
}
}
I still get an error. This time on the let aHashable: T?
stored property:
Use of undeclared type 'T'
What's the right way to get what I want? Thank you.
Upvotes: 1
Views: 273
Reputation: 299703
The T
you want in this case is Never
, since it can never have a value. To define that kind of init, you need to constrain it in an extension like this:
extension MyStruct where T == Never {
init(aBool: Bool, aInt: Int) {
self.init(aBool: aBool, aInt: aInt, aHashable: nil)
}
}
IMO, Swift should also allow this as:
init(aBool: Bool, aInt: Int) where T == Never {...}
But that's not currently legal Swift. You have to put it in an extension. It's just a syntax issue.
For completeness, here's the full code:
struct MyStruct<T> where T: Hashable {
let aBool: Bool
let aInt: Int
let aHashable: T?
init(aHashable: T?) {
self.init(aBool: false, aInt: 0, aHashable: aHashable)
}
private init(aBool: Bool, aInt: Int, aHashable: T?) {
self.aBool = aBool
self.aInt = aInt
self.aHashable = aHashable
}
}
extension MyStruct where T == Never {
init(aBool: Bool, aInt: Int) {
self.init(aBool: aBool, aInt: aInt, aHashable: nil)
}
}
let myStruct = MyStruct(aBool: true, aInt: 10)
Upvotes: 2
Reputation: 502
try this way
struct MyStruct<T: Hashable> {
let aBool: Bool
let aInt: Int
let aHashable: T?
init(aBool: Bool, aInt: Int) {
self.init(aBool: aBool, aInt: aInt, aHashable: nil)
}
init(aHashable: T?) {
self.init(aBool: false, aInt: 0, aHashable: aHashable)
}
private init(aBool: Bool, aInt: Int, aHashable: T?) {
self.aBool = aBool
self.aInt = aInt
self.aHashable = aHashable
}
}
than
let myStruct = MyStruct<'Your Hashable Type'>(aBool: true, aInt: 10)
Upvotes: 0