У світі програмування іноді виникають ситуації, коли потрібно віднімати між собою множини елементів. У мові програмування Swift для цього існують спеціальні типи даних, такі як NSCountedSet, які забезпечують можливість виконання операції віднімання наборів. Однак, коли ці набори містять елементи структур Swift, виникають особливості, які варто врахувати для коректної реалізації операції віднімання.
Розглянемо ситуацію, коли маємо два NSCountedSet, що містять елементи простої структури Swift під назвою MyStruct. Для наочності, структура MyStruct містить лише одне властивість – name. Потрібно відняти один набір від іншого і отримати результат.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
```swift struct MyStruct { let name: String init(_ name: String) { self.name = name } } func subtract(_ set1: NSCountedSet, _ set2: NSCountedSet) -> NSCountedSet { var result = NSCountedSet() for e in set1 { let count1 = set1.count(for: e) let count2 = set2.count(for: e) let newCount = count1 - count2 if newCount > 0 { for _ in 1 ... newCount { result.add(e) } } } return result } let set1 = NSCountedSet(array: [MyStruct("A"), MyStruct("A"), MyStruct("A"), MyStruct("B"), MyStruct("C"), MyStruct("C")]) let set2 = NSCountedSet(array: [MyStruct("A"), MyStruct("B"), MyStruct("C")]) let set3 = subtract(set1, set2) // expected result: ["A", "A", "C"] print(set3.count(for: MyStruct("A"))) // observed result: 0 (expected 2) print(set3.count(for: MyStruct("B"))) // observed result: 0 (expected 0) print(set3.count(for: MyStruct("C"))) // observed result: 0 (expected 1) |
Однак, при роботі зі структурами Swift виникає особливість у порівнянні елементів. Кожен екземпляр структури вважається унікальним, навіть якщо їх властивості мають однакові значення. Це призводить до того, що порівняння екземплярів MyStruct напряму може не давати очікуваних результатів. У наданих прикладах, count1 завжди повертає 1, що показує, що елементи не збігаються, як очікувалося.
Для вирішення цієї проблеми ми можемо реалізувати власне порівняння для екземплярів структури на основі їх властивостей. У нашому випадку, ми можемо порівнювати екземпляри за їх властивістю name.
1 2 3 4 5 6 7 8 9 10 11 |
```swift extension MyStruct: Hashable { static func == (lhs: MyStruct, rhs: MyStruct) -> Bool { return lhs.name == rhs.name } func hash(into hasher: inout Hasher) { hasher.combine(name) } } ``` |
Шляхом розширення структури MyStruct протоколом Hashable та перевизначенням оператора ==
і методу hash(into:)
, ми забезпечуємо порівняння екземплярів MyStruct за їх властивістю name.
Після впровадження цього рішення, функція віднімання повинна працювати так, як очікувалося, враховуючи екземпляри MyStruct з однаковим ім’ям як рівнозначні.
Якщо виникають схожі проблеми з іншими власними структурами, важливо реалізувати власну логіку порівняння на основі їх властивостей, щоб уникнути таких невідповідностей.
`