enum Suit: String {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
}
Misalnya, bagaimana saya bisa melakukan sesuatu seperti:
for suit in Suit {
// do something with suit
print(suit.rawValue)
}
Contoh yang dihasilkan:
♠
♥
♦
♣
Jawaban:
Swift 4.2+
Dimulai dengan Swift 4.2 (dengan Xcode 10), tambahkan saja kesesuaian protokol
CaseIterable
untuk mendapat manfaatallCases
. Untuk menambahkan kesesuaian protokol ini, Anda hanya perlu menulis di suatu tempat:Jika enum adalah milik Anda, Anda dapat menentukan kesesuaian langsung dalam deklarasi:
Kemudian kode berikut akan mencetak semua nilai yang mungkin:
Kompatibilitas dengan versi Swift sebelumnya (3.x dan 4.x)
Jika Anda perlu mendukung Swift 3.x atau 4.0, Anda dapat meniru implementasi Swift 4.2 dengan menambahkan kode berikut:
sumber
String
, sebagai lawan dari pertanyaan Stack Overflow saat ini.Posting ini relevan di sini https://www.swift-studies.com/blog/2014/6/10/enumerating-enums-in-swift
Pada dasarnya solusi yang diusulkan adalah
sumber
Enum.Values(typeof(FooEnum))
tetapi diekspos sebagai metode ekstensi (seperti peta atau kurangi).FooEnum.values() :: values(EnumType -> [EnumType])
Saya membuat fungsi utilitas
iterateEnum()
untuk iterasi kasus untukenum
tipe yang sewenang-wenang .Berikut adalah contoh penggunaannya:
Output yang mana:
Tapi, ini hanya untuk keperluan debug atau tes : Ini bergantung pada beberapa perilaku kompiler Swift1.1 yang tidak berdokumen, jadi, gunakan dengan risiko Anda sendiri.
Ini kodenya:
Ide dasarnya adalah:
enum
, tidak termasukenum
s dengan tipe terkait, hanya indeks kasus ketika jumlah kasus2...256
, identik denganUInt8
, kapan257...65536
, ituUInt16
dan seterusnya. Jadi, itu bisaunsafeBitcast
dari tipe integer yang tidak ditandatangani..hashValue
nilai enum sama dengan indeks kasus ini..hashValue
dari enum nilai bitcasted dari tidak valid indeks0
.Direvisi untuk Swift2 dan menerapkan gagasan casting dari jawaban @ Kametrixom :
Direvisi untuk Swift3:
Direvisi untuk Swift3.0.1:
sumber
withUnsafePointer
withMemoryRebound
danpointee
hal - hal, maka gunakan ini dengan segala cara. Kalau tidak, aku akan menghindarinya.Solusi lain bekerja tetapi mereka semua membuat asumsi misalnya jumlah peringkat dan pakaian yang mungkin, atau apa peringkat pertama dan terakhir. Benar, tata letak setumpuk kartu mungkin tidak akan banyak berubah di masa mendatang. Secara umum, bagaimanapun, lebih rapi untuk menulis kode yang membuat asumsi sesedikit mungkin. Solusi saya:
Saya telah menambahkan jenis mentah ke
Suit
enum, jadi saya bisa gunakanSuit(rawValue:)
untuk mengaksesSuit
kasing:Di bawah penerapan
createDeck()
metode Kartu .init(rawValue:)
adalah inisialisasi yang tersedia dan mengembalikan opsional. Dengan membuka dan memeriksa nilainya dalam kedua pernyataan sementara, tidak perlu mengasumsikan jumlahRank
atauSuit
kasus:Inilah cara memanggil
createDeck
metode:sumber
Suit
. Anda bisa dalam contoh ini, tetapi latihan itu dimaksudkan untuk membuat Anda bekerja denganenums
Anda diberikan seolah-olah mereka berasal dari sumber eksternal.Saya tersandung dalam bit dan byte dan menciptakan ekstensi yang kemudian saya temukan bekerja sangat mirip dengan jawaban @rintaro . Ini digunakan seperti ini:
Yang luar biasa adalah bahwa ini dapat digunakan pada enum apa pun tanpa nilai terkait. Perhatikan bahwa ini tidak berfungsi untuk enum yang tidak memiliki kasing.
Seperti halnya jawaban @rintaro , kode ini menggunakan representasi enum yang mendasarinya. Representasi ini tidak didokumentasikan dan mungkin berubah di masa depan, yang akan mematahkannya. Saya tidak merekomendasikan penggunaan ini dalam produksi.
Kode (Swift 2.2, Xcode 7.3.1, tidak bekerja pada Xcode 10):
Kode (Swift 3, Xcode 8.1, tidak bekerja pada Xcode 10):
Saya tidak tahu mengapa saya perlu
typealias
, tetapi kompiler mengeluh tanpa itu.sumber
withUnsafePointer
…pointee}
bywithUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } }
Anda bisa melakukan iterasi melalui enum dengan mengimplementasikan
ForwardIndexType
protokol.The
ForwardIndexType
protokol mengharuskan Anda untuk menentukansuccessor()
fungsi untuk langkah melalui elemen.Iterasi melalui rentang terbuka atau tertutup (
..<
atau...
) akan memanggilsuccessor()
fungsi yang memungkinkan Anda untuk menulis ini:sumber
successor()
Metode yang didefinisikan dengan benar (opsi pertama) akan menghilangkan kebutuhan untukenum
memiliki jenis terkait. +1Masalah ini sekarang jauh lebih mudah. Inilah Solusi Swift 4.2 saya:
Pre 4.2:
Saya suka solusi ini yang saya kumpulkan setelah menemukan " Daftar pemahaman dalam Swift ".
Ia menggunakan Int raw bukan Strings tetapi ia menghindari mengetik dua kali, itu memungkinkan menyesuaikan rentang, dan tidak menyulitkan kode nilai mentah.
Ini adalah versi Swift 4 dari solusi asli saya tetapi lihat peningkatan 4.2 di atas:
sumber
Pada prinsipnya adalah mungkin untuk melakukannya dengan asumsi bahwa Anda tidak menggunakan penetapan nilai mentah untuk kasus enum:
sumber
enum ItWontWorkForThisEnum {case a, b, c}
Jika Anda memberikan enum nilai Int mentah itu akan membuat perulangan jauh lebih mudah.
Misalnya, Anda dapat menggunakan
anyGenerator
untuk mendapatkan generator yang dapat menyebutkan nilai Anda:Namun, ini terlihat seperti pola yang cukup umum, bukankah lebih baik jika kita dapat membuat enum type enumerable dengan hanya menyesuaikan dengan protokol? Baik dengan Swift 2.0 dan ekstensi protokol, sekarang kita bisa!
Cukup tambahkan ini ke proyek Anda:
Sekarang, setiap kali Anda membuat enum (asalkan memiliki nilai mentah Int), Anda dapat membuatnya enumerable dengan mematuhi protokol:
Jika nilai enum Anda tidak dimulai dengan
0
(default), gantifirstRawValue
metode:Kelas Suit akhir, termasuk mengganti
simpleDescription
dengan protokol CustomStringConvertible yang lebih standar , akan terlihat seperti ini:Sintaks Swift 3:
sumber
Diperbarui ke Swift 2.2 +
Kode ini diperbarui ke formulir Swift 2.2 @ Kametrixom's answer
Untuk Swift 3.0+ (terima kasih banyak ke @Philip )
sumber
Solusi Swift 5:
sumber
Saya menemukan diri saya melakukan
.allValues
banyak hal di seluruh kode saya. Saya akhirnya menemukan cara untuk sekadar menyesuaikan diri denganIteratable
protokol dan memilikirawValues()
metode.sumber
Xcode 10 dengan Swift 4.2
Sebut saja
Cetakan:
Versi yang lebih lama
Untuk
enum
mewakiliInt
Sebut saja seperti ini:
Cetakan:
Untuk
enum
mewakiliString
Sebut saja
Cetakan:
sumber
EDIT: Swift Evolution Proposal SE-0194 Berasal Koleksi Kasus Enum mengusulkan tingkat menuju solusi untuk masalah ini. Kami melihatnya di Swift 4.2 dan yang lebih baru. Proposal juga menunjukkan beberapa solusi yang mirip dengan beberapa yang telah disebutkan di sini, tetapi mungkin menarik untuk dilihat.
Saya juga akan menyimpan posting asli saya demi kelengkapan.
Ini adalah pendekatan lain berdasarkan jawaban @ Peymmankh, disesuaikan dengan Swift 3 .
sumber
Bagaimana dengan ini?
sumber
Anda dapat mencoba menghitung seperti ini
sumber
static var enumerate = [Mercury, Venus, Earth, Mars]
, menjadikannya jawaban di bawah standar dibandingkan dengan jawaban terbanyak yang dipilih stackoverflow.com/a/24137319/1033581return [Mercury, Venus, Mars]
alih-alihreturn [Mercury, Venus, Earth, Mars]
return [.spades, .hearts, .clubs]
kompiler tidak akan mengatakan apa-apa dan kemudian ketika Anda mencoba menggunakannya dalam kode, Anda akan mendapatkan[TestApp.Suit.spades, TestApp.Suit.hearts, TestApp.Suit.clubs]
- itu maksud saya - bahwa jika Anda berurusan dengan besar enum dan Anda harus menambah atau menghapus kasus dari waktu ke waktu, solusi Anda rentan terhadap kesalahan kelalaian sementara jawaban saat ini, meskipun tidak singkat, lebih aman.Di Swift 3, ketika enum yang mendasarinya
rawValue
, Anda bisa mengimplementasikanStrideable
protokol. Keuntungannya adalah tidak ada array nilai yang dibuat seperti pada beberapa saran lain dan bahwa Swift standar "for in" bekerja, yang membuat sintaks yang bagus.sumber
Solusi ini memberikan keseimbangan yang tepat antara keterbacaan dan pemeliharaan.
sumber
Maaf, jawaban saya khusus untuk bagaimana saya menggunakan posting ini dalam apa yang harus saya lakukan. Bagi mereka yang menemukan pertanyaan ini, mencari cara untuk menemukan kasus dalam enum, inilah cara untuk melakukannya (baru dalam Swift 2):
Sunting: camelCase huruf kecil sekarang menjadi standar untuk nilai Swift 3 enum
Bagi mereka yang bertanya-tanya tentang enumerasi pada enum, jawaban yang diberikan pada halaman ini yang menyertakan var statis / biarkan berisi array semua nilai enum benar. Contoh kode Apple terbaru untuk tvOS berisi teknik yang sama persis ini.
Yang sedang berkata, mereka harus membangun mekanisme yang lebih nyaman ke dalam bahasa (Apple, apakah Anda mendengarkan?)!
sumber
Eksperimennya adalah: EKSPERIMEN
Tambahkan metode ke Kartu yang membuat setumpuk penuh kartu, dengan satu kartu dari setiap kombinasi peringkat dan kartu.
Jadi tanpa memodifikasi atau meningkatkan kode yang diberikan selain menambahkan metode (dan tanpa menggunakan hal-hal yang belum diajarkan), saya datang dengan solusi ini:
sumber
Berikut adalah metode yang saya gunakan untuk kedua iterate
enum
dan memberikan beberapa tipe nilai dari satuenum
Ini hasilnya:
Angka Nol dalam bahasa Prancis: zéro, Spanyol: cero, Jepang: nuru
Nomor satu dalam bahasa Prancis: un, bahasa Spanyol: uno, Jepang: ichi
Nomor dua dalam bahasa Prancis: deux, spanyol: dos, Jepang: ni
Nomor Tiga dalam bahasa perancis : trois, spanyol: tres, Jepang: san
Angka Empat dalam bahasa Prancis: quatre, Spanyol: cuatro, Jepang: shi
Angka lima dalam bahasa Prancis: cinq, bahasa Spanyol: cinco, jepang: go
Nomor Enam dalam bahasa Prancis: enam, spanyol: seis, Jepang: roku
Nomor Tujuh dalam bahasa Prancis: sept, spanyol: siete, Jepang: shichi
Total 8 kasus
siete dalam bahasa Jepang: shichi
MEMPERBARUI
Saya baru-baru ini membuat protokol untuk menangani enumerasi. Protokol membutuhkan enum dengan nilai mentah Int:
sumber
Sepertinya ini peretasan tetapi jika Anda menggunakan nilai mentah, Anda dapat melakukan sesuatu seperti ini
sumber
Saat berurusan dengan di
Swift 2.0
sini adalah saran saya:Saya telah menambahkan jenis mentah ke
Suit
enum
kemudian:
sumber
Seperti halnya jawaban @Kametrixom di sini saya percaya mengembalikan array akan lebih baik daripada mengembalikan AnySequence, karena Anda dapat memiliki akses ke semua barang Array seperti hitungan, dll.
Inilah re-write:
sumber
Solusi lain:
sumber
Ini adalah pos yang cukup lama, dari Swift 2.0. Sekarang ada beberapa solusi yang lebih baik di sini yang menggunakan fitur-fitur baru swift 3.0: Iterating melalui Enum di Swift 3.0
Dan pada pertanyaan ini ada solusi yang menggunakan fitur baru (yang belum dirilis saat saya menulis suntingan ini) Swift 4.2: Bagaimana cara saya mendapatkan hitungan enum Swift?
Ada banyak solusi bagus di utas ini dan yang lainnya namun beberapa di antaranya sangat rumit. Saya suka menyederhanakan sebanyak mungkin. Berikut ini adalah solusi yang mungkin atau mungkin tidak berfungsi untuk kebutuhan yang berbeda tetapi saya pikir ini berfungsi dengan baik dalam kebanyakan kasus:
Untuk beralih:
sumber
Enum punya
toRaw()
danfromRaw()
metode. Jadi, jika nilai mentah Anda adalahInt
, Anda dapat beralih dari yang pertama ke yang terakhirenum
:Satu gotcha adalah bahwa Anda perlu menguji nilai-nilai opsional sebelum menjalankan
simpleDescription
metode, jadi kami menetapkanconvertedSuit
nilai kami terlebih dahulu dan kemudian menetapkan konstanta untukconvertedSuit.simpleDescription()
sumber
Inilah pendekatan yang saya sarankan. Ini tidak sepenuhnya memuaskan (saya sangat baru di Swift dan OOP!) Tapi mungkin seseorang dapat memperbaikinya. Idenya adalah meminta masing-masing enum menyediakan informasi
.first
dan.last
properti jangkauannya sendiri . Ia menambahkan hanya dua baris kode untuk masing-masing enum: masih agak sulit dikodekan, tetapi setidaknya itu tidak menduplikasi seluruh rangkaian. Itu memang mengharuskan memodifikasiSuit
enum menjadi Int sepertiRank
enum, bukan untyped.Daripada mengulangi seluruh solusi, inilah kode yang saya tambahkan ke
.
enum, di suatu tempat setelah pernyataan kasus (Suit
enum serupa):dan loop yang saya gunakan untuk membangun dek sebagai array dari String. (Definisi masalah tidak menyatakan bagaimana deck akan disusun.)
Ini tidak memuaskan karena sifat-sifatnya terkait dengan suatu elemen daripada enum. Tapi itu menambah kejelasan pada loop 'untuk'. Saya ingin mengatakannya
Rank.first
sebagai gantiRank.Ace.first
. Ini bekerja (dengan elemen apa pun), tapi jelek. Adakah yang bisa menunjukkan cara menaikkan itu ke level enum?Dan untuk membuatnya bekerja, saya mengangkat
createDeck
metode keluar dari struct Kartu. Saya tidak tahu bagaimana cara mendapatkan array [String] kembali dari struct itu, dan itu tampaknya tempat yang buruk untuk meletakkan metode seperti itu pula.sumber
Saya melakukannya dengan menggunakan properti yang dihitung, yang mengembalikan array dari semua nilai (berkat posting ini http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ ). Namun, ini juga menggunakan nilai mentah int, tapi saya tidak perlu mengulangi semua anggota enumerasi di properti terpisah.
PEMBARUAN Xcode 6.1 sedikit mengubah cara mendapatkan anggota enum
rawValue
, jadi saya memperbaiki daftar. Juga memperbaiki kesalahan kecil dengan kesalahan terlebih dahulurawValue
.sumber
Berdasarkan jawaban Rick: ini 5 kali lebih cepat
sumber
Count
case akan merusakswitch
implementasi danCaseIterable
kesesuaian yang lengkap.