Jadikan kesamaan dan pencincangan Swift tersuai menggunakan satu takrif nilai tidak berubah. Panduan ini membina kunci jubin setempat yang namanya tidak membezakan huruf besar dan kecil, manakala dimensinya kekal tepat, kemudian menyemak kesamaan, keahlian dalam set dan carian kamus.
Tentukan dengan tepat bila dua jubin dianggap sama
Katakan anda sedang membina latihan grafik desktop Mac yang ringkas. Anda perlu mengumpulkan huraian jubin sintetik mengikut nama, lebar dan tinggi. Tugas pembaca ialah melaksanakan pengumpulan itu secara konsisten: Orbit dan ORBIT pada dimensi yang sama sepatutnya menghasilkan kunci yang sama; mengubah mana-mana dimensi sepatutnya menghasilkan kunci yang berbeza.
Tuliskan kontrak sebelum melaksanakan mana-mana protokol. Untuk contoh ini, dua kunci adalah sama apabila nama yang dilipat huruf besar dan kecilnya, lebar dan tingginya adalah sama. Dimensi ialah unit lukisan integer positif. Ruang di hadapan dan di belakang nama kekal penting. Ini ialah peraturan aplikasi yang dijadikan contoh, bukannya keperluan yang ditetapkan oleh Swift.
| Input sintetik | Hubungan yang dijangka | Sebab |
|---|---|---|
Orbit, 40 × 20 dan ORBIT, 40 × 20 |
Sama | Huruf besar dan kecil diabaikan |
Orbit, 40 × 20 dan orbit, 41 × 20 |
Tidak sama | Lebar diambil kira dalam kesamaan |
Orbit, 40 × 20 dan orbit, 40 × 21 |
Tidak sama | Tinggi diambil kira dalam kesamaan |
Orbit, 40 × 20 dan orbit , 40 × 20 |
Tidak sama | Ruang di belakang dikekalkan |
Gunakan kunci khusus apabila peraturan pengumpulan tertentu berbeza daripada nilai penuh jubin yang dipaparkan. Kekalkan ejaan asal untuk paparan dalam model persembahan yang mengelilinginya. Dengan cara itu, anda tidak mengisytiharkan dua huraian jubin lengkap sebagai saling boleh ganti sedangkan nama yang kelihatan berbeza menjadi sebahagian daripada nilainya. Dokumentasi Equatable Swift menghuraikan kesamaan dari segi kebolehgantian dan mensyaratkan refleksiviti, simetri serta transitiviti. Equatable
Gunakan komponen yang sama untuk kesamaan dan pencincangan
Protokol Hashable Swift mewarisi Equatable. Keperluan asasnya ialah tika yang sama mesti membekalkan nilai yang sama kepada hasher dalam susunan yang sama. Nilai Hashable boleh digunakan sebagai unsur set dan kunci kamus. Hashable
Kesilapan yang kerap berlaku ialah membandingkan nama yang dinormalkan dalam == tetapi mencincang ejaan asal. Maka, nama tersebut membawa maksud yang berbeza dalam kedua-dua kaedah. Kesilapan lain ialah menggugurkan lebar daripada kesamaan tetapi memasukkannya dalam pencincangan. Kedua-dua reka bentuk ini membolehkan nilai yang diisytiharkan sama membekalkan input pencincangan yang berbeza. Apple mengarahkan pelaksanaan tersuai supaya menggunakan sifat penting yang sama dalam kedua-dua kaedah. Mengguna Pakai Protokol Lazim
Untuk contoh ini, letakkan komponen kesamaan dalam struktur tersarang peribadi. Biarkan Swift mensintesis kesamaan dan pencincangan struktur itu, kemudian serahkan kedua-dua operasi luar kepadanya. Dengan cara ini, senarai komponen hanya diisytiharkan sekali dan mudah diperiksa. Swift menyokong pematuhan tersintesis untuk struktur yang sifat tersimpannya mematuhi protokol yang diperlukan. Protokol — Mengguna Pakai Protokol Menggunakan Pelaksanaan Tersintesis
Jika jenis anda sudah menyimpan komponen kesamaannya sahaja, pematuhan Hashable tersintesis biasanya sudah mencukupi. Kaedah luar yang dinyatakan secara jelas di bawah menunjukkan cara memastikan pelaksanaan tersuai sedia ada kekal selaras tanpa menyelenggara dua senarai medan yang berasingan.
Jalankan contoh setempat yang lengkap pada Mac anda
Anda memerlukan toolchain Swift yang telah dipasang bersama Foundation. Dalam Terminal, semak dengan swift --version, seperti yang disyorkan dalam dokumentasi permulaan Swift. Jika Swift tidak tersedia, ikuti panduan pemasangan rasmi macOS sebelum meneruskan. Bermula, Pasang Swift — macOS
Berikut ialah satu arahan shell lengkap yang mengandungi program Swift. Tampal seluruh blok ke dalam Terminal. Arahan ini membekalkan program melalui input standard; contoh ini hanya menjalankan pengiraan dalam memori dan mencetak hasilnya. Kod Swift telah diperiksa tetapi tidak dapat dijalankan dalam persekitaran penyelidikan kerana Swift tidak tersedia.
swift - <<'SWIFT'
import Foundation
struct TileKey: Hashable, Sendable {
private struct Components: Hashable, Sendable {
let foldedName: String
let width: Int
let height: Int
}
private let components: Components
init(name: String, width: Int, height: Int) {
precondition(width > 0 && height > 0,
"Tile dimensions must be positive")
let foldedName = name.folding(
options: [.caseInsensitive],
locale: Locale(identifier: "en_US_POSIX")
)
components = Components(
foldedName: foldedName,
width: width,
height: height
)
}
static func == (lhs: TileKey, rhs: TileKey) -> Bool {
lhs.components == rhs.components
}
func hash(into hasher: inout Hasher) {
hasher.combine(components)
}
}
let a = TileKey(name: "Orbit", width: 40, height: 20)
let b = TileKey(name: "ORBIT", width: 40, height: 20)
let c = TileKey(name: "orbit", width: 40, height: 20)
let wider = TileKey(name: "orbit", width: 41, height: 20)
let taller = TileKey(name: "orbit", width: 40, height: 21)
let spaced = TileKey(name: "orbit ", width: 40, height: 20)
let samples = [a, b, c, wider, taller, spaced]
precondition(a == b && b == c && a == c)
precondition(a != wider && a != taller && a != spaced)
// Check the equality laws over this finite sample.
for first in samples {
precondition(first == first, "Reflexivity failed")
for second in samples {
precondition((first == second) == (second == first),
"Symmetry failed")
if first == second {
precondition(first.hashValue == second.hashValue,
"Equal values have different hashes")
}
for third in samples where first == second && second == third {
precondition(first == third, "Transitivity failed")
}
}
}
let uniqueKeys = Set(samples)
precondition(uniqueKeys.count == 4)
precondition(uniqueKeys.contains(b))
let patterns = [a: "striped"]
precondition(patterns[b] == "striped")
print("Unique keys:", uniqueKeys.count)
print("Equivalent key found:", uniqueKeys.contains(b))
print("Pattern:", patterns[b] ?? "missing")
print("Sample contract checks passed")
SWIFT
Output yang dijangka:
Kunci unik: 4
Kunci setara ditemui: true
Corak: berjalur
Semakan kontrak sampel lulus
Enam input itu membentuk empat kumpulan: tiga variasi huruf besar dan kecil berkongsi satu kunci, manakala perubahan lebar, perubahan tinggi dan variasi dengan ruang di belakang masing-masing membentuk kumpulan yang lain. Semakan kamus menguji sama ada nilai yang dikaitkan dengan a boleh diperoleh menggunakan kunci setara b. Semakan ini menguji tingkah laku koleksi yang dikehendaki tanpa bergantung pada mana-mana nilai cincangan berangka tertentu.
Pemula sengaja menghentikan proses jika dimensinya bukan positif. Itu sesuai untuk latihan sintetik yang tetap ini, yang menganggap dimensi tidak sah sebagai kesilapan pengaturcaraan. Jika antara muka desktop membenarkan kemasukan dimensi yang belum lengkap, sahkan input itu sebelum membina kunci, atau ubah pemula supaya memulangkan nilai opsyenal atau melontarkan ralat. Jangan gantikan dimensi secara senyap kerana itu mengubah kontrak kesamaan.
Jadikan penormalan teks peraturan yang jelas
Langkah penormalan memanggil folding(options:locale:) daripada Foundation melalui API rentetan Swift. API itu memulangkan rentetan dengan pilihan pelipatan yang ditentukan diterapkan. Di sini, hanya .caseInsensitive diminta. StringProtocol.folding(options:locale:)
Foundation mendokumenkan pelipatan huruf besar dan kecil, lebar serta diakritik sebagai pilihan berasingan. Foundation juga menerangkan bahawa lokal boleh mengubah hasil pelipatan dan teks yang dilipat mungkin tidak sesuai untuk paparan. Oleh itu, contoh ini membekalkan lokal tetap dan hanya menyimpan hasil yang dilipat di dalam kunci. Nama sintetiknya sengaja dipilih agar ringkas. Pilihan lokal ini mentakrifkan tingkah laku latihan ini; ia bukan saranan sejagat untuk setiap antara muka penamaan. NSString.folding(options:locale:)
Keputusan reka bentuk yang berguna ialah menormalkan sekali semasa pembinaan. Selepas itu, kesamaan dan pencincangan menggunakan hasil yang disimpan, jadi kedua-dua operasi tidak memilih lokal atau transformasi secara berasingan. Jika aplikasi kemudian memerlukan dasar perbandingan yang berbeza, bina kunci menggunakan dasar baharu itu dan bina semula koleksi dalam memori yang terjejas.
Sebelum memperluas penormalan, tambahkan contoh yang membezakan kumpulan yang dikehendaki. Patutkah ruang diambil kira? Patutkah huruf beraksen kekal berbeza? Patutkah lebar aksara yang kelihatan berbeza dianggap nama yang sama? Tetapkan jawapan sebagai peraturan produk, kemudian laksanakan satu transformasi yang digunakan oleh kedua-dua operasi.
Kenal pasti ketidakpadanan tanpa mempercayai nilai cincangan
Gunakan urutan berikut apabila menyesuaikan reka bentuk ini kepada jenis sedia ada:
- Tulis satu pasangan yang mesti dibandingkan sebagai sama dan satu pasangan bagi setiap medan yang mesti membezakan nilai.
- Jejaki nilai sebenar yang dibandingkan oleh
==, termasuk penormalan dan sifat terbitan. - Jejaki nilai yang dibekalkan kepada
hasher.combine, termasuk susunannya. - Pindahkan takrif bersama itu ke dalam satu nilai komponen tidak berubah, atau pastikan kedua-dua pelaksanaan menggunakan komponen yang sama secara jelas.
- Semak hukum kesamaan, cincangan nilai yang sama, keahlian dalam set dan carian kamus menggunakan lekapan yang sama.
Jangan laksanakan kesamaan dengan membandingkan hashValue. Nilai yang sama mesti mempunyai cincangan yang sama, tetapi cincangan yang sepadan tidak membuktikan kesamaan. Komponen kesamaan penuh kekal sebagai asas bagi ==. Begitu juga, ujian yang mensyaratkan setiap pasangan yang tidak sama mempunyai cincangan yang berbeza menuntut lebih daripada yang dijamin oleh kontrak pencincangan. Hashable
Bandingkan cincangan hanya dalam pelaksanaan semasa apabila menyemak kontrak ini. Hasher Swift menggunakan pemula rawak dan algoritmanya mungkin berubah antara versi pustaka standard. Oleh itu, integer yang dicetak daripada larian semalam tidak sesuai dijadikan hasil jangkaan untuk larian hari ini. Hasher
Semakan sampel terhingga berguna sebagai semakan regresi, tetapi bukan bukti untuk setiap rentetan dan dimensi yang mungkin. Hujah strukturnya juga penting: kedua-dua kaedah luar menyerahkan tugas kepada nilai Components yang tidak berubah dan medan tersimpannya menyatakan sepenuhnya kontrak yang dipilih.
Asingkan keperluan konkurensi daripada kesamaan
Contoh ini mengisytiharkan kedua-dua struktur sebagai Sendable kerana nilai tersimpannya ialah rentetan, integer dan satu lagi struktur yang boleh dihantar. Swift mendokumenkan bahawa struktur Sendable mesti mengandungi sifat tersimpan yang juga Sendable. Sendability berkaitan dengan pemindahan nilai antara domain konkurensi; ia tidak menentukan nilai mana yang dibandingkan sebagai sama. Sendable, Bahasa Pengaturcaraan Swift — Konkurensi
Pengiraan setempat ini tidak memerlukan tugas atau aktor. Jika kemudian menjadi sebahagian daripada kod desktop yang berjalan serentak, kekalkan kesamaan dan pencincangan sebagai operasi segerak pada komponen tersimpan kunci. Kendalikan sebarang koleksi boleh ubah yang dikongsi sebagai isu reka bentuk konkurensi yang berasingan. Panduan bahasa menghuraikan aktor dan pengasingan sebagai mekanisme untuk menyelaraskan akses kepada keadaan boleh ubah. Bahasa Pengaturcaraan Swift — Konkurensi
Terdapat juga sempadan Foundation apabila menyesuaikan corak ini: subkelas NSObject menggunakan tingkah laku kesamaan dan pencincangan yang diwarisi. Laluan penyesuaian yang disokong Apple ialah mengatasi isEqual(_:) dan hash bersama-sama. Struktur Swift biasa dalam contoh ini menggunakan == dan hash(into:). Mengguna Pakai Protokol Lazim
Untuk kunci jubin setempat, hasil yang mudah diselenggara ialah peraturan perbandingan bertulis, satu perwakilan tidak berubah bagi peraturan itu dan semakan yang menguji carian koleksi sebenar. Apabila takrif berubah, kemas kini perwakilan komponen dan contohnya bersama-sama supaya kesamaan dan pencincangan terus menerangkan nilai yang sama.
Sumber
- Hashable — Apple
- Equatable — Apple
- Hasher — Apple
- Mengguna Pakai Protokol Lazim — Apple
- folding(options:locale:) — StringProtocol — Apple
- folding(options:locale:) — NSString — Apple
- Sendable — Apple
- Protokol — Bahasa Pengaturcaraan Swift, Swift.org
- Konkurensi — Bahasa Pengaturcaraan Swift, Swift.org
- Bermula — Swift.org
- Pasang Swift — macOS — Swift.org