@@ -107,22 +107,33 @@ internal struct _ConcreteHashableBox<Base: Hashable>: _AnyHashableBox {
107
107
/// A type-erased hashable value.
108
108
///
109
109
/// The `AnyHashable` type forwards equality comparisons and hashing operations
110
- /// to an underlying hashable value, hiding its specific underlying type.
110
+ /// to an underlying hashable value, hiding the type of the wrapped value.
111
+ ///
112
+ /// Where conversion using `as` or `as?` is possible between two types (such as
113
+ /// `Int` and `NSNumber`), `AnyHashable` uses a canonical representation of the
114
+ /// type-erased value so that instances wrapping the same value of either type
115
+ /// compare as equal. For example, `AnyHashable(42)` compares as equal to
116
+ /// `AnyHashable(42 as NSNumber)`.
111
117
///
112
118
/// You can store mixed-type keys in dictionaries and other collections that
113
119
/// require `Hashable` conformance by wrapping mixed-type keys in
114
120
/// `AnyHashable` instances:
115
121
///
116
122
/// let descriptions: [AnyHashable: Any] = [
117
- /// AnyHashable("😄"): "emoji",
118
- /// AnyHashable(42): "an Int",
119
- /// AnyHashable(Int8(43)): "an Int8",
120
- /// AnyHashable(Set(["a", "b"])): "a set of strings"
123
+ /// 42: "an Int",
124
+ /// 43 as Int8: "an Int8",
125
+ /// ["a", "b"] as Set: "a set of strings"
121
126
/// ]
122
- /// print(descriptions[AnyHashable(42)]!) // prints "an Int"
123
- /// print(descriptions[AnyHashable(45)]) // prints "nil"
124
- /// print(descriptions[AnyHashable(Int8(43))]!) // prints "an Int8"
125
- /// print(descriptions[AnyHashable(Set(["a", "b"]))]!) // prints "a set of strings"
127
+ /// print(descriptions[42]!) // prints "an Int"
128
+ /// print(descriptions[42 as Int8]!) // prints "an Int"
129
+ /// print(descriptions[43 as Int8]!) // prints "an Int8"
130
+ /// print(descriptions[44]) // prints "nil"
131
+ /// print(descriptions[["a", "b"] as Set]!) // prints "a set of strings"
132
+ ///
133
+ /// Note that `AnyHashable` does not guarantee that it preserves the hash
134
+ /// encoding of wrapped values. Do not rely on `AnyHashable` generating such
135
+ /// compatible hashes, as the hash encoding that it uses may change between any
136
+ /// two releases of the standard library.
126
137
@frozen
127
138
public struct AnyHashable {
128
139
internal var _box : _AnyHashableBox
@@ -154,7 +165,7 @@ public struct AnyHashable {
154
165
/// The value wrapped by this instance.
155
166
///
156
167
/// The `base` property can be cast back to its original type using one of
157
- /// the casting operators (`as?`, `as!`, or `as`).
168
+ /// the type casting operators (`as?`, `as!`, or `as`).
158
169
///
159
170
/// let anyMessage = AnyHashable("Hello world!")
160
171
/// if let unwrappedMessage = anyMessage.base as? String {
@@ -189,11 +200,23 @@ public struct AnyHashable {
189
200
190
201
extension AnyHashable : Equatable {
191
202
/// Returns a Boolean value indicating whether two type-erased hashable
192
- /// instances wrap the same type and value.
203
+ /// instances wrap the same value.
193
204
///
194
- /// Two instances of `AnyHashable` compare as equal if and only if the
195
- /// underlying types have the same conformance to the `Equatable` protocol
196
- /// and the underlying values compare as equal.
205
+ /// `AnyHashable` considers bridged counterparts (such as a `String` and an
206
+ /// `NSString`) of the same value to be equivalent when type-erased. If those
207
+ /// compatible types use different definitions for equality, values that were
208
+ /// originally distinct might compare as equal when they are converted to
209
+ /// `AnyHashable`:
210
+ ///
211
+ /// let string1 = "café"
212
+ /// let string2 = "cafe\u{301}" // U+301 COMBINING ACUTE ACCENT
213
+ /// let nsString1 = string1 as NSString
214
+ /// let nsString2 = string2 as NSString
215
+ /// let typeErased1 = nsString1 as AnyHashable
216
+ /// let typeErased2 = nsString2 as AnyHashable
217
+ /// print(string1 == string2) // prints "true"
218
+ /// print(nsString1 == nsString2) // prints "false"
219
+ /// print(typeErased1 == typeErased2) // prints "true"
197
220
///
198
221
/// - Parameters:
199
222
/// - lhs: A type-erased hashable value.
@@ -204,16 +227,10 @@ extension AnyHashable: Equatable {
204
227
}
205
228
206
229
extension AnyHashable : Hashable {
207
- /// The hash value.
208
230
public var hashValue : Int {
209
231
return _box. _canonicalBox. _hashValue
210
232
}
211
233
212
- /// Hashes the essential components of this value by feeding them into the
213
- /// given hasher.
214
- ///
215
- /// - Parameter hasher: The hasher to use when combining the components
216
- /// of this instance.
217
234
public func hash( into hasher: inout Hasher ) {
218
235
_box. _canonicalBox. _hash ( into: & hasher)
219
236
}
0 commit comments