The goal was to convert items in a generic list into a dictionary for the variable uniqueKeys
, but I saw the error:
Cannot subscript a value of incorrect or ambiguous type
I knew something needed to conform to the Hashable
protocol and eventually landed on the solution, but I don't completely understand why this solution works.
T
needs to be Hashable
since its' going into a dictionary key, but why also CustomSet
? CustomSet
uses Hashable
why don't I need to write anything in its extension?initial code
struct CustomSet<T : Comparable > {
private var list: [T]
init(_ list: [T]){
let uniqueKeys = list.reduce(into: [:]){ dict, item in
dict[item, default: 0] += 1
}.keys
self.list = Array(uniqueKeys)
}
}
extension CustomSet : Equatable {
static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
return lhs.list.count == rhs.list.count && lhs.list.sorted() == rhs.list.sorted()
}
}
I finally resolved it with:
struct CustomSet<T : Comparable > : Hashable where T : Hashable {
private var list: [T]
init(_ list: [T]){
let uniqueKeys = list.reduce(into: [:]){ dict, item in
dict[item, default: 0] += 1
}.keys
self.list = Array(uniqueKeys)
}
}
extension CustomSet : Equatable {
static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
return lhs.list.count == rhs.list.count && lhs.list.sorted() == rhs.list.sorted()
}
}
I also noticed that factoring into an extension: extension CustomSet: Hashable where T : Hashable
doesn't seem to be the same as struct CustomSet<T : Comparable > : Hashable where T : Hashable
in terms of adding the Hashable protocol because I still see that error
What I tried
If I add this to the generic type T
I still saw the same error.
struct CustomSet<T : Comparable, Hashable >
If I add Hashable
to CustomSet
I see the error
Cannot convert value of type '[T]' to expected argument type 'UnsafeRawBufferPointer'
and
Inheritance from non-protocol type 'Hashable'
extension CustomSet : Equatable, Hashable {
static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
return lhs.list.count == rhs.list.count && lhs.list.sorted() == rhs.list.sorted()
}
func hash(into hasher: inout Hasher) {
var hashValue: Int {
var hasher = Hasher()
self.hash(into: &hasher)
return hasher.finalize()
}
}
}
There's no need to make CustomSet
conform to Hashable
. Simply adding the Hashable
restriction to the generic type parameter solves the error
Cannot subscript a value of incorrect or ambiguous type
,which is expected, since a Dictionary
's keys need to conform to Hashable
.
Btw the syntax for declaring conformance to several protocols is &
, not ,
, so there's no need for the where clause.
struct CustomSet<T : Comparable & Hashable> {
private var list: [T]
init(_ list: [T]){
let uniqueKeys = list.reduce(into: [:]){ dict, item in
dict[item, default: 0] += 1
}.keys
self.list = Array(uniqueKeys)
}
}
extension CustomSet : Equatable {
static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
return lhs.list.count == rhs.list.count && lhs.list.sorted() == rhs.list.sorted()
}
}
Moreover, you can simply do self.list = Array(Set(list))
in the initializer to store only the unique elements from the input in your list
, there's no need for messing around with a Dictionary
.