Go’da enum va iota
Go’da alohida enum kalit so‘zi yo‘q. Enumga o‘xshash qiymatlar nomlangan tur va konstantalar bilan yaratiladi. iota esa const guruhi ichida ketma-ket sonlarni yozishni ixchamlashtiradi.
Nomlangan tur va konstantalar
package main
import "fmt"
type Status int
const (
StatusUnknown Status = iota
StatusPending
StatusProcessing
StatusCompleted
)
func main() {
status := StatusProcessing
fmt.Println(status)
fmt.Println(status == StatusCompleted)
}
Natija:
Status nomlangan tur bo‘lgani uchun koddagi ma’no oddiy intdan aniqroq. StatusUnknownni nol qiymatga qo‘yish foydali: var status Status tasodifan haqiqiy biznes holatini bildirmaydi.
iota qanday ishlaydi?
iota har bir const guruhida 0 dan boshlanadi va har bir ConstSpec satrida bittaga oshadi. Ifoda yozilmagan satr oldingi ifoda va uning turini takrorlaydi:
Bir satrda bir nechta konstanta bo‘lsa, ular uchun iota bir xil bo‘ladi. _ orqali ayrim qiymatni tashlab ketish mumkin:
Bu yerda birinchi satr _ga beriladi, keyingi qiymatlar mos ravishda 1024, 1048576 va 1073741824 bo‘ladi.
Matn ko‘rinishini berish
Nomlangan turga String metodi qo‘shilsa, fmt uni o‘qilishi qulay ko‘rinishda chiqaradi:
package main
import "fmt"
type Status int
const (
StatusUnknown Status = iota
StatusPending
StatusProcessing
StatusCompleted
)
func (s Status) String() string {
switch s {
case StatusUnknown:
return "unknown"
case StatusPending:
return "pending"
case StatusProcessing:
return "processing"
case StatusCompleted:
return "completed"
default:
return fmt.Sprintf("Status(%d)", s)
}
}
func main() {
fmt.Println(StatusProcessing)
fmt.Println(Status(99))
}
Natija:
default noma’lum qiymatni yashirmaydi. Bu log va diagnostikada foydali. Katta enumlar uchun String metodini generatsiya qiluvchi vositalar ishlatilishi mumkin, ammo generatsiya natijasi repozitoriy qoidalariga muvofiq boshqariladi.
Enum yopiq to‘plam emas
Muhim farq: nomlangan son turiga istalgan mos sonni ochiq konvertatsiya qilish mumkin — Status(99) kompilyatsiyadan o‘tadi. Demak, Go’dagi bu usul qiymatlarni mutlaq cheklamaydi. Tashqi input, JSON yoki database qiymatini qabul qilganda validatsiya kerak:
Konstantalarni database yoki tarmoq protokolida saqlasangiz, o‘rtaga yangi iota qiymati qo‘shish keyingi raqamlarni siljitadi. Bunday formatlarda aniq sonlarni yozish yoki faqat oxiriga yangi qiymat qo‘shish xavfsizroq.
Bit bayroqlar
iota bitmask yaratishda ham ishlatiladi:
type Permission uint8
const (
PermissionRead Permission = 1 << iota
PermissionWrite
PermissionDelete
)
func has(value, permission Permission) bool {
return value&permission != 0
}
Bu oddiy ketma-ket enum emas: qiymatlar 1, 2, 4 bo‘lib, | bilan birlashtiriladi. Masalan, PermissionRead | PermissionWrite ikkala ruxsatni saqlaydi.
Xulosa
- Go’da enum alohida til konstruksiyasi emas; nomlangan tur va konstantalar ishlatiladi.
iotaconstguruhidagi satrlar bo‘yicha oshadi va har yangi guruhda nolga qaytadi.- Nol qiymatni
Unknownholatiga ajratish xavfsiz dizayn beradi. - Istalgan sonni nomlangan turga konvertatsiya qilish mumkin, shu sabab tashqi qiymat validatsiya qilinadi.
- Barqaror tashqi formatlarda
iotaraqamlarining siljishiga ehtiyot bo‘lish kerak.
Misollar
1. Hafta kunlarini birdan boshlash
Bu misolda iota + 1 yordamida hafta kunlariga 1 dan boshlab qiymat beriladi.
package main
import "fmt"
type Weekday int
const (
Monday Weekday = iota + 1
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
func main() {
fmt.Println(Monday, Wednesday, Sunday)
}
iota odatda 0 dan boshlanadi. + 1 birinchi qiymatni 1 qiladi, keyingi satrlar esa 2, 3 va shu tartibda davom etadi. Bu raqamlarni foydalanuvchi ko‘radigan hafta kunlari bilan moslashtirishga yordam beradi.
2. Nol qiymatni noma’lum holat uchun saqlash
Bu misolda tur e’lon qilinganda olinadigan nol qiymat alohida Unknown holatini bildiradi.
package main
import "fmt"
type DeliveryStatus int
const (
DeliveryUnknown DeliveryStatus = iota
DeliveryAccepted
DeliveryOnTheWay
DeliveryArrived
)
func main() {
var status DeliveryStatus
fmt.Println(status == DeliveryUnknown)
status = DeliveryOnTheWay
fmt.Println(status)
}
statusga boshlang‘ich qiymat berilmagani uchun u 0 bo‘ladi. DeliveryUnknown ham 0 bo‘lgani sababli hali holat tanlanmagani aniq ko‘rinadi. Haqiqiy jarayon holatlari 1 dan boshlanadi.
3. Keraksiz birinchi qiymatni tashlab ketish
Bu misolda _ birinchi iota qiymatini nom bermasdan o‘tkazib yuboradi.
package main
import "fmt"
type Priority int
const (
_ Priority = iota
PriorityLow
PriorityMedium
PriorityHigh
)
func main() {
fmt.Println(PriorityLow, PriorityMedium, PriorityHigh)
}
Birinchi satrda iota 0 ga teng, lekin qiymat _ga yozilgani uchun undan foydalanib bo‘lmaydi. Natijada darajalar 1, 2 va 3 qiymatlarini oladi. Bu 0 haqiqiy daraja bo‘lmasligi kerak bo‘lgan holatda qulay.
4. Qiymatlarni o‘n qadam bilan oshirish
Bu misolda iota formula ichida ishlatilib, bo‘lim kodlari orasida joy qoldiriladi.
package main
import "fmt"
type DepartmentCode int
const (
DepartmentSales DepartmentCode = (iota + 1) * 10
DepartmentSupport
DepartmentWarehouse
)
func main() {
fmt.Println(DepartmentSales, DepartmentSupport, DepartmentWarehouse)
}
Birinchi satrda iota 0, shuning uchun (0 + 1) * 10 natijasi 10 bo‘ladi. Keyingi qiymatlar 20 va 30. Formuladagi + 1 birinchi kodning 0 bo‘lib qolishiga yo‘l qo‘ymaydi.
5. Bir satrda bog‘liq qiymatlar yaratish
Bu misolda bitta iota qiymatidan diapazonning boshi va oxiri hisoblanadi.
package main
import "fmt"
const (
SmallMin, SmallMax = iota * 10, iota*10 + 9
MediumMin, MediumMax
LargeMin, LargeMax
)
func main() {
fmt.Println(SmallMin, SmallMax)
fmt.Println(MediumMin, MediumMax)
fmt.Println(LargeMin, LargeMax)
}
Bir ConstSpec satridagi ikkala iota ham bir xil qiymatga ega. Shu sabab diapazonlar 0–9, 10–19 va 20–29 ko‘rinishida hosil bo‘ladi. Keyingi satrlarda ifodani qayta yozish shart emas.
6. Har bir const guruhida qayta boshlash
Bu misol iota yangi const guruhi ochilganda yana 0 dan boshlanishini ko‘rsatadi.
package main
import "fmt"
const (
North = iota
East
)
const (
Draft = iota
Published
)
func main() {
fmt.Println(North, East)
fmt.Println(Draft, Published)
}
Birinchi guruhdagi qiymatlar 0 va 1. Ikkinchi guruh avvalgisini davom ettirmaydi: Draft yana 0, Published esa 1 bo‘ladi. Alohida enumlar shu tariqa bir-biriga ta’sir qilmaydi.
7. Fayl ruxsatlarini birlashtirish
Bu misolda ikkilik bayroqlar | operatori bilan bitta qiymatda saqlanadi.
package main
import "fmt"
type FilePermission uint8
const (
CanRead FilePermission = 1 << iota
CanWrite
CanExecute
)
func main() {
permissions := CanRead | CanWrite
fmt.Println(permissions)
fmt.Println(permissions&CanRead != 0)
fmt.Println(permissions&CanExecute != 0)
}
1 << iota qiymatlarni 1, 2 va 4 qiladi. Ularning bitlari ustma-ust tushmaydi. permissions&CanRead != 0 o‘qish biti yoqilganini, permissions&CanExecute != 0 esa bajarish biti yoqilmaganini tekshiradi.
8. Bayroqni qiymatdan olib tashlash
Bu misolda &^ operatori yoqilgan bayroqlardan bittasini o‘chiradi.
package main
import "fmt"
type Notification uint8
const (
NotifyEmail Notification = 1 << iota
NotifySMS
NotifyPush
)
func main() {
settings := NotifyEmail | NotifySMS | NotifyPush
settings &^= NotifySMS
fmt.Println(settings&NotifyEmail != 0)
fmt.Println(settings&NotifySMS != 0)
fmt.Println(settings&NotifyPush != 0)
}
Boshlanishida uchala bayroq ham | orqali yoqiladi. &^= o‘ng tomondagi NotifySMS bitini tozalaydi, qolgan bitlarni o‘zgartirmaydi. Shu sabab natijalar true, false, true bo‘ladi.
9. Enum qiymatlarini matnga aylantirish
Bu misolda switch asosidagi metod buyurtma holatini o‘qilishi qulay matn bilan qaytaradi.
package main
import "fmt"
type OrderStatus int
const (
OrderNew OrderStatus = iota
OrderPaid
OrderSent
)
func (s OrderStatus) Label() string {
switch s {
case OrderNew:
return "yangi"
case OrderPaid:
return "to‘langan"
case OrderSent:
return "yuborilgan"
default:
return "noma’lum"
}
}
func main() {
fmt.Println(OrderPaid.Label())
fmt.Println(OrderStatus(20).Label())
}
Label() sonli qiymatni foydalanuvchiga tushunarli matnga o‘giradi. default tanilmagan son uchun ishlaydi. Chunki OrderStatus(20) kabi ochiq konvertatsiya enum ro‘yxatida bo‘lmagan qiymatni ham yaratishi mumkin.
10. Tashqi format uchun aniq kodlarni saqlash
Bu misolda tashqi tizim bilan almashiladigan kodlar iota o‘rniga aniq sonlar bilan beriladi.
package main
import "fmt"
type PaymentCode int
const (
PaymentCreated PaymentCode = 100
PaymentApproved PaymentCode = 200
PaymentRejected PaymentCode = 400
)
func main() {
codes := []PaymentCode{PaymentCreated, PaymentApproved, PaymentRejected}
for _, code := range codes {
fmt.Println(code)
}
}
Bu qiymatlar tashqi API yoki database bilan kelishilgan deb tasavvur qilinadi. Aniq son yozilgani uchun konstantalar orasiga yangi holat qo‘shish mavjud kodlarni siljitmaydi. Slice tartibi 100, 200, 400 qiymatlarini ketma-ket ko‘rsatish uchun tanlangan.