[Swift]实现Swift的两个协议:Hashable协议和Equatable协议(Type does not conform to protocol 'Hashable')...

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/ 
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/10815581.html 
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

【Command 】+【鼠标右键】-> 【Jump to Definition】

Hashable协议:

 1 public protocol Hashable : Equatable {
 2 
 3     /// The hash value.
 4     ///
 5     /// Hash values are not guaranteed to be equal across different executions of
 6     /// your program. Do not save hash values to use during a future execution.
 7     ///
 8     /// - Important: `hashValue` is deprecated as a `Hashable` requirement. To
 9     ///   conform to `Hashable`, implement the `hash(into:)` requirement instead.
10     var hashValue: Int { get }
11 
12     /// Hashes the essential components of this value by feeding them into the
13     /// given hasher.
14     ///
15     /// Implement this method to conform to the `Hashable` protocol. The
16     /// components used for hashing must be the same as the components compared
17     /// in your type's `==` operator implementation. Call `hasher.combine(_:)`
18     /// with each of these components.
19     ///
20     /// - Important: Never call `finalize()` on `hasher`. Doing so may become a
21     ///   compile-time error in the future.
22     ///
23     /// - Parameter hasher: The hasher to use when combining the components
24     ///   of this instance.
25     func hash(into hasher: inout Hasher)
26 }

翻译版本:

 1 public protocol Hashable : Equatable {
 2     ///散列值。
 3     //
 4     ///不能保证哈希值在不同的
 5     ///你的程序。不要保存哈希值以在将来执行时使用。
 6     //
 7     ///-重要提示:“hashvalue”被弃用为“hashable”要求。到
 8     ///符合“hashable”,改为实现“hash(into:)”要求。
 9 
10     var hashValue: Int { get }
11 
12     ///通过将此值的基本组件放入
13     ///给定哈希。
14     //
15     ///实现此方法以符合“hashable”协议。这个
16     ///用于散列的组件必须与比较的组件相同
17     ///在类型的`=`运算符实现中。调用'hasher.combine(:)`
18     ///每个组件。
19     //
20     ///-重要提示:不要在“hasher”上调用“finalize()”。这样做可能会成为
21     ///将来出现编译时错误。
22     //
23     ///-参数散列器:组合组件时要使用的散列器
24     ///此实例的。
25 
26     func hash(into hasher: inout Hasher)
27 }

Equatable 协议:

  1 /// A type-erased hashable value.
  2 
  3 ///
  4 
  5 /// The `AnyHashable` type forwards equality comparisons and hashing operations
  6 
  7 /// to an underlying hashable value, hiding its specific underlying type.
  8 
  9 ///
 10 
 11 /// You can store mixed-type keys in dictionaries and other collections that
 12 
 13 /// require `Hashable` conformance by wrapping mixed-type keys in
 14 
 15 /// `AnyHashable` instances:
 16 
 17 ///
 18 
 19 ///     let descriptions: [AnyHashable: Any] = [
 20 
 21 ///         AnyHashable("?"): "emoji",
 22 
 23 ///         AnyHashable(42): "an Int",
 24 
 25 ///         AnyHashable(Int8(43)): "an Int8",
 26 
 27 ///         AnyHashable(Set(["a", "b"])): "a set of strings"
 28 
 29 ///     ]
 30 
 31 ///     print(descriptions[AnyHashable(42)]!)      // prints "an Int"
 32 
 33 ///     print(descriptions[AnyHashable(43)])       // prints "nil"
 34 
 35 ///     print(descriptions[AnyHashable(Int8(43))]!) // prints "an Int8"
 36 
 37 ///     print(descriptions[AnyHashable(Set(["a", "b"]))]!) // prints "a set of strings"
 38 
 39 public struct AnyHashable {
 40 
 41 
 42 
 43/// Creates a type-erased hashable value that wraps the given instance.
 44 
 45///
 46 
 47/// The following example creates two type-erased hashable values: `x` wraps
 48 
 49/// an `Int` with the value 42, while `y` wraps a `UInt8` with the same
 50 
 51/// numeric value. Because the underlying types of `x` and `y` are
 52 
 53/// different, the two variables do not compare as equal despite having
 54 
 55/// equal underlying values.
 56 
 57///
 58 
 59///     let x = AnyHashable(Int(42))
 60 
 61///     let y = AnyHashable(UInt8(42))
 62 
 63///
 64 
 65///     print(x == y)
 66 
 67///     // Prints "false" because `Int` and `UInt8` are different types
 68 
 69///
 70 
 71///     print(x == AnyHashable(Int(42)))
 72 
 73///     // Prints "true"
 74 
 75///
 76 
 77/// - Parameter base: A hashable value to wrap.
 78 
 79public init<H>(_ base: H) where H : Hashable
 80 
 81 
 82 
 83/// The value wrapped by this instance.
 84 
 85///
 86 
 87/// The `base` property can be cast back to its original type using one of
 88 
 89/// the casting operators (`as?`, `as!`, or `as`).
 90 
 91///
 92 
 93///     let anyMessage = AnyHashable("Hello world!")
 94 
 95///     if let unwrappedMessage = anyMessage.base as? String {
 96 
 97///         print(unwrappedMessage)
 98 
 99///     }
100 
101///     // Prints "Hello world!"
102 
103public var base: Any { get }
104 
105 
106 
107public static func != (lhs: AnyHashable, rhs: AnyHashable) -> Bool
108 
109 }
110 
111 
112 
113 extension AnyHashable : Equatable {
114 
115 
116 
117/// Returns a Boolean value indicating whether two type-erased hashable
118 
119/// instances wrap the same type and value.
120 
121///
122 
123/// Two instances of `AnyHashable` compare as equal if and only if the
124 
125/// underlying types have the same conformance to the `Equatable` protocol
126 
127/// and the underlying values compare as equal.
128 
129///
130 
131/// The following example creates two type-erased hashable values: `x` wraps
132 
133/// an `Int` with the value 42, while `y` wraps a `UInt8` with the same
134 
135/// numeric value. Because the underlying types of `x` and `y` are
136 
137/// different, the two variables do not compare as equal despite having
138 
139/// equal underlying values.
140 
141///
142 
143///     let x = AnyHashable(Int(42))
144 
145///     let y = AnyHashable(UInt8(42))
146 
147///
148 
149///     print(x == y)
150 
151///     // Prints "false" because `Int` and `UInt8` are different types
152 
153///
154 
155///     print(x == AnyHashable(Int(42)))
156 
157///     // Prints "true"
158 
159///
160 
161/// - Parameters:
162 
163///   - lhs: A type-erased hashable value.
164 
165///   - rhs: Another type-erased hashable value.
166 
167public static func == (lhs: AnyHashable, rhs: AnyHashable) -> Bool
168 
169 }
170 
171 
172 
173 extension AnyHashable : Hashable {
174 
175 
176 
177/// The hash value.
178 
179public var hashValue: Int { get }
180 
181 
182 
183/// Hashes the essential components of this value by feeding them into the
184 
185/// given hasher.
186 
187///
188 
189/// - Parameter hasher: The hasher to use when combining the components
190 
191///   of this instance.
192 
193public func hash(into hasher: inout Hasher)
194 
195 }
196 
197 
198 
199 extension AnyHashable : CustomStringConvertible {
200 
201 
202 
203/// A textual representation of this instance.
204 
205///
206 
207/// Calling this property directly is discouraged. Instead, convert an
208 
209/// instance of any type to a string by using the `String(describing:)`
210 
211/// initializer. This initializer works with any type, and uses the custom
212 
213/// `description` property for types that conform to
214 
215/// `CustomStringConvertible`:
216 
217///
218 
219///     struct Point: CustomStringConvertible {
220 
221///         let x: Int, y: Int
222 
223///
224 
225///         var description: String {
226 
227///             return "(\(x), \(y))"
228 
229///         }
230 
231///     }
232 
233///
234 
235///     let p = Point(x: 21, y: 30)
236 
237///     let s = String(describing: p)
238 
239///     print(s)
240 
241///     // Prints "(21, 30)"
242 
243///
244 
245/// The conversion of `p` to a string in the assignment to `s` uses the
246 
247/// `Point` type's `description` property.
248 
249public var description: String { get }
250 
251 }
252 
253 
254 
255 extension AnyHashable : CustomDebugStringConvertible {
256 
257 
258 
259/// A textual representation of this instance, suitable for debugging.
260 
261///
262 
263/// Calling this property directly is discouraged. Instead, convert an
264 
265/// instance of any type to a string by using the `String(reflecting:)`
266 
267/// initializer. This initializer works with any type, and uses the custom
268 
269/// `debugDescription` property for types that conform to
270 
271/// `CustomDebugStringConvertible`:
272 
273///
274 
275///     struct Point: CustomDebugStringConvertible {
276 
277///         let x: Int, y: Int
278 
279///
280 
281///         var debugDescription: String {
282 
283///             return "(\(x), \(y))"
284 
285///         }
286 
287///     }
288 
289///
290 
291///     let p = Point(x: 21, y: 30)
292 
293///     let s = String(reflecting: p)
294 
295///     print(s)
296 
297///     // Prints "(21, 30)"
298 
299///
300 
301/// The conversion of `p` to a string in the assignment to `s` uses the
302 
303/// `Point` type's `debugDescription` property.
304 
305public var debugDescription: String { get }
306 
307 }
308 
309 
310 
311 extension AnyHashable : CustomReflectable {
312 
313 
314 
315/// The custom mirror for this instance.
316 
317///
318 
319/// If this type has value semantics, the mirror should be unaffected by
320 
321/// subsequent mutations of the instance.
322 
323public var customMirror: Mirror { get }
324 
325 }
326 
327 
328 
329 /// A type that can be hashed into a `Hasher` to produce an integer hash value.
330 
331 ///
332 
333 /// You can use any type that conforms to the `Hashable` protocol in a set or as
334 
335 /// a dictionary key. Many types in the standard library conform to `Hashable`:
336 
337 /// Strings, integers, floating-point and Boolean values, and even sets are
338 
339 /// hashable by default. Some other types, such as optionals, arrays and ranges
340 
341 /// automatically become hashable when their type arguments implement the same.
342 
343 ///
344 
345 /// Your own custom types can be hashable as well. When you define an
346 
347 /// enumeration without associated values, it gains `Hashable` conformance
348 
349 /// automatically, and you can add `Hashable` conformance to your other custom
350 
351 /// types by implementing the `hash(into:)` method. For structs whose stored
352 
353 /// properties are all `Hashable`, and for enum types that have all-`Hashable`
354 
355 /// associated values, the compiler is able to provide an implementation of
356 
357 /// `hash(into:)` automatically.
358 
359 ///
360 
361 /// Hashing a value means feeding its essential components into a hash function,
362 
363 /// represented by the `Hasher` type. Essential components are those that
364 
365 /// contribute to the type's implementation of `Equatable`. Two instances that
366 
367 /// are equal must feed the same values to `Hasher` in `hash(into:)`, in the
368 
369 /// same order.
370 
371 ///
372 
373 /// Conforming to the Hashable Protocol
374 
375 /// ===================================
376 
377 ///
378 
379 /// To use your own custom type in a set or as the key type of a dictionary,
380 
381 /// add `Hashable` conformance to your type. The `Hashable` protocol inherits
382 
383 /// from the `Equatable` protocol, so you must also satisfy that protocol's
384 
385 /// requirements.
386 
387 ///
388 
389 /// The compiler automatically synthesizes your custom type's `Hashable` and
390 
391 /// requirements when you declare `Hashable` conformance in the type's original
392 
393 /// declaration and your type meets these criteria:
394 
395 ///
396 
397 /// - For a `struct`, all its stored properties must conform to `Hashable`.
398 
399 /// - For an `enum`, all its associated values must conform to `Hashable`. (An
400 
401 ///   `enum` without associated values has `Hashable` conformance even without
402 
403 ///   the declaration.)
404 
405 ///
406 
407 /// To customize your type's `Hashable` conformance, to adopt `Hashable` in a
408 
409 /// type that doesn't meet the criteria listed above, or to extend an existing
410 
411 /// type to conform to `Hashable`, implement the `hash(into:)` method in your
412 
413 /// custom type.
414 
415 ///
416 
417 /// In your `hash(into:)` implementation, call `combine(_:)` on the provided
418 
419 /// `Hasher` instance with the essential components of your type. To ensure
420 
421 /// that your type meets the semantic requirements of the `Hashable` and
422 
423 /// `Equatable` protocols, it's a good idea to also customize your type's
424 
425 /// `Equatable` conformance to match.
426 
427 ///
428 
429 /// As an example, consider a `GridPoint` type that describes a location in a
430 
431 /// grid of buttons. Here's the initial declaration of the `GridPoint` type:
432 
433 ///
434 
435 ///     /// A point in an x-y coordinate system.
436 
437 ///     struct GridPoint {
438 
439 ///         var x: Int
440 
441 ///         var y: Int
442 
443 ///     }
444 
445 ///
446 
447 /// You'd like to create a set of the grid points where a user has already
448 
449 /// tapped. Because the `GridPoint` type is not hashable yet, it can't be used
450 
451 /// in a set. To add `Hashable` conformance, provide an `==` operator function
452 
453 /// and implement the `hash(into:)` method.
454 
455 ///
456 
457 ///     extension GridPoint: Hashable {
458 
459 ///         static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
460 
461 ///             return lhs.x == rhs.x && lhs.y == rhs.y
462 
463 ///         }
464 
465 ///
466 
467 ///         func hash(into hasher: inout Hasher) {
468 
469 ///             hasher.combine(x)
470 
471 ///             hasher.combine(y)
472 
473 ///         }
474 
475 ///     }
476 
477 ///
478 
479 /// The `hash(into:)` method in this example feeds the grid point's `x` and `y`
480 
481 /// properties into the provided hasher. These properties are the same ones
482 
483 /// used to test for equality in the `==` operator function.
484 
485 ///
486 
487 /// Now that `GridPoint` conforms to the `Hashable` protocol, you can create a
488 
489 /// set of previously tapped grid points.
490 
491 ///
492 
493 ///     var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]
494 
495 ///     let nextTap = GridPoint(x: 0, y: 1)
496 
497 ///     if tappedPoints.contains(nextTap) {
498 
499 ///         print("Already tapped at (\(nextTap.x), \(nextTap.y)).")
500 
501 ///     } else {
502 
503 ///         tappedPoints.insert(nextTap)
504 
505 ///         print("New tap detected at (\(nextTap.x), \(nextTap.y)).")
506 
507 ///     }
508 
509 ///     // Prints "New tap detected at (0, 1).")
510 
511 public protocol Hashable : Equatable {
512 
513 
514 
515/// The hash value.
516 
517///
518 
519/// Hash values are not guaranteed to be equal across different executions of
520 
521/// your program. Do not save hash values to use during a future execution.
522 
523///
524 
525/// - Important: `hashValue` is deprecated as a `Hashable` requirement. To
526 
527///   conform to `Hashable`, implement the `hash(into:)` requirement instead.
528 
529var hashValue: Int { get }
530 
531 
532 
533/// Hashes the essential components of this value by feeding them into the
534 
535/// given hasher.
536 
537///
538 
539/// Implement this method to conform to the `Hashable` protocol. The
540 
541/// components used for hashing must be the same as the components compared
542 
543/// in your type's `==` operator implementation. Call `hasher.combine(_:)`
544 
545/// with each of these components.
546 
547///
548 
549/// - Important: Never call `finalize()` on `hasher`. Doing so may become a
550 
551///   compile-time error in the future.
552 
553///
554 
555/// - Parameter hasher: The hasher to use when combining the components
556 
557///   of this instance.
558 
559 ​    func hash(into hasher: inout Hasher)
560 
561 }
562 
563 
564 
565 /// The universal hash function used by `Set` and `Dictionary`.
566 
567 ///
568 
569 /// `Hasher` can be used to map an arbitrary sequence of bytes to an integer
570 
571 /// hash value. You can feed data to the hasher using a series of calls to
572 
573 /// mutating `combine` methods. When you've finished feeding the hasher, the
574 
575 /// hash value can be retrieved by calling `finalize()`:
576 
577 ///
578 
579 ///     var hasher = Hasher()
580 
581 ///     hasher.combine(23)
582 
583 ///     hasher.combine("Hello")
584 
585 ///     let hashValue = hasher.finalize()
586 
587 ///
588 
589 /// Within the execution of a Swift program, `Hasher` guarantees that finalizing
590 
591 /// it will always produce the same hash value as long as it is fed the exact
592 
593 /// same sequence of bytes. However, the underlying hash algorithm is designed
594 
595 /// to exhibit avalanche effects: slight changes to the seed or the input byte
596 
597 /// sequence will typically produce drastic changes in the generated hash value.
598 
599 ///
600 
601 /// - Note: Do not save or otherwise reuse hash values across executions of your
602 
603 ///   program. `Hasher` is usually randomly seeded, which means it will return
604 
605 ///   different values on every new execution of your program. The hash
606 
607 ///   algorithm implemented by `Hasher` may itself change between any two
608 
609 ///   versions of the standard library.
610 
611 public struct Hasher {
612 
613 
614 
615/// Creates a new hasher.
616 
617///
618 
619/// The hasher uses a per-execution seed value that is set during process
620 
621/// startup, usually from a high-quality random source.
622 
623public init()
624 
625 
626 
627/// Adds the given value to this hasher, mixing its essential parts into the
628 
629/// hasher state.
630 
631///
632 
633/// - Parameter value: A value to add to the hasher.
634 
635 ​    @inlinable public mutating func combine<H>(_ value: H) where H : Hashable
636 
637 
638 
639/// Adds the contents of the given buffer to this hasher, mixing it into the
640 
641/// hasher state.
642 
643///
644 
645/// - Parameter bytes: A raw memory buffer.
646 
647public mutating func combine(bytes: UnsafeRawBufferPointer)
648 
649 
650 
651/// Finalizes the hasher state and returns the hash value.
652 
653///
654 
655/// Finalizing consumes the hasher: it is illegal to finalize a hasher you
656 
657/// don't own, or to perform operations on a finalized hasher. (These may
658 
659/// become compile-time errors in the future.)
660 
661///
662 
663/// Hash values are not guaranteed to be equal across different executions of
664 
665/// your program. Do not save hash values to use during a future execution.
666 
667///
668 
669/// - Returns: The hash value calculated by the hasher.
670 
671public __consuming func finalize() -> Int
672 
673 }

【Command 】+【鼠标右键】-> 【Show Quick Help】

可以散列到散列器中以生成整数散列值的类型。

protocol Hashable : Equatable

您可以在集合中使用任何符合哈希协议的类型,也可以将其用作字典键。标准库中的许多类型都符合hashable:字符串、整数、浮点值和布尔值,默认情况下,偶数集都是可以hashable的。当一些其他类型(如选项、数组和范围)的类型参数实现相同时,它们会自动变为可哈希类型。

您自己的自定义类型也可以是哈希类型。当您定义一个没有关联值的枚举时,它会自动获得哈希一致性,并且您可以通过实现hash(into:)方法将哈希一致性添加到其他自定义类型中。对于其存储属性都是可哈希的结构,以及对于具有所有可哈希关联值的枚举类型,编译器能够自动提供哈希(into:)的实现。

散列值意味着将其基本组件输入散列函数,由散列类型表示。基本组成部分是那些有助于类型的实现等价的部分。两个相等的实例必须以相同的顺序向哈希(in to:)中的哈希器提供相同的值。

符合哈希协议

要在集合中使用您自己的自定义类型或将其用作字典的键类型,请将哈希一致性添加到您的类型中。哈希协议继承自等价协议,因此您还必须满足该协议的要求。

当您在类型的原始声明中声明可哈希一致性并且您的类型满足以下条件时,编译器会自动合成您的自定义类型的可哈希性和要求:

对于结构,其所有存储属性都必须符合哈希表。

对于枚举,其所有关联值都必须符合哈希表。(没有关联值的枚举即使没有声明也具有哈希一致性。)

要自定义类型的哈希一致性,要在不符合上面列出的条件的类型中采用哈希,或者要扩展现有类型以符合哈希,请在自定义类型中实现哈希(in to:)方法。

在散列(into:)实现中,在提供的散列器实例上使用类型的基本组件调用combine(u:)。为了确保您的类型满足哈希和等价协议的语义要求,最好还自定义类型的等价一致性以匹配。

例如,考虑描述按钮网格中位置的网格点类型。以下是网格点类型的初始声明:

1 //X-Y坐标系中的点。
2 struct GridPoint {
3       var x: Int
4       var y: Int
5 }

您想创建一组用户已经点击的网格点。由于GridPoint类型尚不可哈希,因此不能在集合中使用。要添加哈希一致性,请提供一个==运算符函数并实现哈希(into:)方法。

 1 extension GridPoint: Hashable {
 2     static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
 3         return lhs.x == rhs.x && lhs.y == rhs.y
 4     }
 5 
 6     func hash(into hasher: inout Hasher) {
 7         hasher.combine(x)
 8         hasher.combine(y)
 9     }
10 }

本例中的hash(into:)方法将网格点的x和y属性馈送到提供的散列器中。这些属性与在==运算符函数中用于测试相等性的属性相同。

现在,网格点符合哈希协议,您可以创建一组以前点击过的网格点。

1 var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]
2 let nextTap = GridPoint(x: 0, y: 1)
3 if tappedPoints.contains(nextTap) {
4     print("Already tapped at (\(nextTap.x), \(nextTap.y)).")
5 } else {
6     tappedPoints.insert(nextTap)
7     print("New tap detected at (\(nextTap.x), \(nextTap.y)).")
8 }
9 // Prints "New tap detected at (0, 1).")

示例:

 1 class Point:Hashable
 2 {
 3     static func == (lhs: Point, rhs: Point) -> Bool {
 4         return lhs.X == rhs.X && lhs.Y == rhs.Y
 5     }
 6     
 7     func hash(into hasher: inout Hasher)
 8     {
 9         hasher.combine(x)
10         hasher.combine(y)
11     }
12     
13     init(_ x:Int,_ y:Int)
14     {
15         self.x = x
16         self.y = y
17     }
18     
19     private var x:Int = 0
20     var X:Int
21     {
22         get{return x}
23         set{x = newValue}
24     }
25     
26     private var y:Int = 0
27     var Y:Int
28     {
29         get{return y}
30         set{y = newValue}
31     }
32 }

点击:Playground测试

 1 var set:Set<Point> = Set<Point>()
 2 let point1:Point = Point(1,1)
 3 let point2:Point = Point(2,2)
 4 let point3:Point = Point(1,1)
 5 print(point1 == point2)
 6 //Print false
 7 print(point1 == point3)
 8 //Print true
 9 set.insert(point1)
10 set.insert(point2)
11 set.insert(point3)
12 print(set)
13 //[__lldb_expr_66.Point, __lldb_expr_66.Point]

 

转载于:https://www.cnblogs.com/strengthen/p/10815581.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值