Goda enum va iota
Go dasturlash tilida boshqa ayrim tillardagi kabi alohida:
kalit so'zi mavjud emas.
Masalan, Java, C# yoki boshqa tillarda ma'lum bir qiymatlar to'plamini enum sifatida e'lon qilish mumkin.
Go'da esa shu vazifa odatda:
- nomlangan tur;
constkonstantalari;- kerak bo'lsa
iota;
yordamida bajariladi.
Masalan, tizimda buyurtmaning holatlari bo'lsin:
Bularni oddiy int sifatida saqlash mumkin:
Lekin bunda qiymatlar oddiy int bo'lib qoladi.
Go'da buning o'rniga alohida nomlangan tur yaratish yaxshiroq:
Keyin konstantalarni shu turga bog'lash mumkin:
Natijada kodda oddiy son bilan emas, ma'nosi aniq bo'lgan Status turi bilan ishlaymiz.
iota esa bu yerda:
qiymatlarini qo'lda yozmaslikka yordam beradi.
Nomlangan tur va konstantalar
Quyidagi misolni ko'ramiz:
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:
Bu koddagi eng muhim qism:
Bu yerda int asosida yangi Status turi yaratildi.
Statusning asosiy turi int, lekin Go uchun u alohida nomlangan tur hisoblanadi.
Keyin:
orqali Status uchun mumkin bo'lgan asosiy konstantalar e'lon qilindi.
Birinchi qatorda:
yozilgan.
const guruhi boshlanganda iota qiymati:
bo'ladi.
Shuning uchun:
Keyingi qatorda yangi ifoda yozilmagan:
Go oldingi ifodani takrorlaydi va iota bittaga oshadi.
Natijada:
Keyingi qiymatlar:
bo'ladi.
Shuning uchun:
natijasi:
bo'ladi.
Keyin:
tekshirilmoqda.
status qiymati:
StatusCompleted esa:
bo'lgani uchun natija:
chiqadi.
Nega oddiy int emas, alohida tur ishlatamiz?
Quyidagicha yozish ham mumkin edi:
Lekin bu qiymatlar oddiy int bo'lib qoladi.
Alohida:
turini yaratish kodning ma'nosini aniqroq qiladi.
Masalan:
funksiyasi ko'rinishidan ham parametr oddiy son emas, aynan tizim holati ekanini tushunish mumkin.
Bu:
ko'rinishidan ancha tushunarli.
Nomlangan turga keyinchalik metodlar ham qo'shish mumkin:
yoki:
Shuning uchun nomlangan tur faqat sonlarga boshqa nom berish emas. U ma'lum bir tushunchani alohida tur sifatida ifodalash imkonini beradi.
Nol qiymatni Unknown uchun ishlatish
Go'da har bir turning zero value, ya'ni boshlang'ich qiymati mavjud.
int asosidagi tur uchun bu:
bo'ladi.
Masalan:
deb yozsak va unga hech qanday qiymat bermasak:
bo'ladi.
Shuning uchun ko'pincha enumga o'xshash turlarda 0 qiymatini:
kabi noma'lum yoki hali belgilanmagan holatga ajratish foydali.
Masalan:
Endi:
deb e'lon qilingan qiymat avtomatik ravishda:
holatiga teng bo'ladi.
Bu yaxshi dizayn, chunki zero value tasodifan haqiqiy biznes holatini bildirmaydi.
Agar birinchi qiymatni:
deb qo'ysak, yangi e'lon qilingan:
tasodifan Completed holatini bildirgan bo'lardi.
Ko'p tizimlarda bu xavfli.
Shuning uchun:
yoki:
kabi holat ajratish yaxshi amaliyot hisoblanadi.
iota qanday ishlaydi?
iota — faqat const deklaratsiyasi ichida ishlatiladigan maxsus identifikator.
U har bir yangi const guruhida:
dan boshlanadi.
Masalan:
qiymatlar:
bo'ladi.
Lekin iotani faqat to'g'ridan-to'g'ri son sifatida ishlatish shart emas.
U formula ichida ham ishlatilishi mumkin.
Masalan:
Natija:
bo'ladi.
Birinchi qatorda:
iota:
bo'ladi.
Demak:
Keyingi qatorda:
uchun alohida ifoda yozilmagan.
Go oldingi:
ifodasini takrorlaydi.
Bu qatorda iota:
bo'lgani uchun:
hosil bo'ladi.
C qatorida esa:
Natija:
Ifoda yozilmagan qator nima qiladi?
Masalan:
aslida quyidagiga yaqin:
Lekin har bir qatorga kelganda iota qiymati bittaga oshib boradi.
Shuning uchun bir xil formulani qayta-qayta yozish shart emas.
Bu iotaning asosiy qulayliklaridan biri.
iota har bir ConstSpec qatorida oshadi
Muhim qoida:
iota har bir konstanta nomida emas, har bir ConstSpec qatorida bittaga oshadi.
Masalan:
Birinchi qator davomida ikkala iota ham:
bo'ladi.
Shuning uchun:
Ikkinchi qatorda esa:
Shuning uchun:
bo'ladi.
Demak, bitta qatorda nechta iota yozilishidan qat'i nazar, ular o'sha qator uchun bir xil qiymatga ega.
Bu keyingi misollarda diapazonlar yaratishda foydali bo'ladi.
_ yordamida iota qiymatini tashlab ketish
Ba'zan iotaning birinchi qiymati kerak bo'lmasligi mumkin.
Masalan, darajalarni:
dan boshlamoqchimiz.
Buning bir usuli:
Boshqa usuli esa _ orqali birinchi qiymatni tashlab ketish:
Birinchi qatorda:
Lekin qiymat:
ga berilgan.
_ — blank identifier.
Bu qiymatdan keyinchalik foydalanib bo'lmaydi.
Keyingi qatorda:
bo'ladi.
Shuning uchun:
hosil bo'ladi.
iota yordamida o'lcham qiymatlari
iota formula bilan ishlashi sabab faqat oddiy:
ketma-ketligini yaratish uchun emas.
Masalan, fayl o'lchamlarini yaratish mumkin:
Bu kod birinchi qarashda murakkab ko'rinishi mumkin.
Bosqichma-bosqich ko'ramiz.
Birinchi qator:
Bu qatorda:
Demak:
ya'ni:
natija:
Lekin bu qiymat _ga berilgan va ishlatilmaydi.
Keyingi qatorda:
oldingi ifoda takrorlanadi.
Bu safar:
Demak:
ya'ni:
Bu:
ga teng.
Shuning uchun:
Keyingi qatorda:
Demak:
Natija:
Keyingi qiymat:
Natija:
Demak:
Bu yerda iota formula ichidagi o'zgaruvchi kabi ishlatildi.
Har bir const guruhida iota qaytadan boshlanadi
iota butun dastur bo'yicha bittadan oshib yurmaydi.
Har safar yangi:
guruhi ochilganda iota yana:
dan boshlanadi.
Masalan:
Natija:
Ikkinchi const guruhi birinchisini davom ettirmaydi.
Bu juda muhim.
Chunki loyihada bir nechta alohida enumga o'xshash turlar bo'lishi mumkin va ularning iota qiymatlari bir-biriga ta'sir qilmaydi.
Matn ko'rinishini berish
Enumga o'xshash qiymatlarning yana bir muammosi bor.
Masalan:
agar hech qanday qo'shimcha metod yozilmagan bo'lsa:
chiqaradi.
Dastur ichida bu son yetarli bo'lishi mumkin.
Lekin:
- loglarda;
- debugging vaqtida;
- CLI dasturda;
- foydalanuvchiga ko'rsatiladigan natijada;
2 nimani anglatishini tushunish qiyin.
Shuning uchun nomlangan turga String() metodini qo'shish mumkin.
Masalan:
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:
Bu qanday ishlaydi?
Status turida:
metodi mavjud:
Bu fmt.Stringer interface'iga mos keladi:
Shuning uchun fmt paketidagi funksiyalar Status qiymatini chiqarayotganda uning String() metodidan foydalanishi mumkin.
Masalan:
oddiy:
o'rniga:
chiqaradi.
switch yordamida nomni tanlash
Metod ichida:
switch s {
case StatusUnknown:
return "unknown"
case StatusPending:
return "pending"
case StatusProcessing:
return "processing"
case StatusCompleted:
return "completed"
}
orqali har bir sonli qiymatga matn berilgan.
Masalan:
qiymati:
bo'lsa ham, String():
qaytaradi.
default nima uchun kerak?
Metod oxirida:
bor.
Buni yozish muhim.
Chunki Go'dagi enumga o'xshash tur faqat e'lon qilingan konstantalar bilan cheklanmagan.
Masalan:
yozish mumkin.
Shuning uchun String() faqat:
qilib yuborsa, haqiqiy noma'lum qiymatni yashirib qo'yishi mumkin.
Buning o'rniga:
chiqishi debugging va loglarda ancha foydali.
Biz darhol:
Tizimga kutilmagan 99 qiymati kelibdi
deb ko'ra olamiz.
Katta enumlarda o'nlab yoki yuzlab case yozish noqulay bo'lishi mumkin.
Bunday holatlarda String() metodini avtomatik generatsiya qiluvchi vositalardan foydalanish mumkin.
Lekin generatsiya qilingan fayllarni loyiha va repozitoriy qoidalariga mos boshqarish kerak.
Enum yopiq to'plam emas
Go'dagi enumga o'xshash yondashuvning juda muhim farqi bor.
Quyidagicha tur yaratdik:
va faqat to'rtta konstanta e'lon qildik:
Bu qiymatlar:
bo'ladi.
Lekin bu:
Statusfaqat 0, 1, 2 yoki 3 bo'lishi mumkin
degani emas.
Quyidagi kod ham kompilyatsiyadan o'tadi:
Bu mutlaqo haqiqiy Status qiymati hisoblanadi.
Shuning uchun Go'dagi bu yondashuv boshqa ayrim tillardagi qat'iy enum kabi yopiq to'plam yaratmaydi.
Nega bu muhim?
Agar qiymatlar faqat o'z kodimiz ichida ishlatilsa, odatda konstantalardan foydalanamiz:
Lekin tashqi manbadan ma'lumot kelganda vaziyat boshqacha.
Masalan:
- HTTP request;
- JSON;
- database;
- message broker;
- fayl;
- boshqa servis;
orqali:
kelishi mumkin.
Uni:
ga aylantirish texnik jihatdan mumkin.
Lekin u biznes qoidalariga mos kelmasligi mumkin.
Shuning uchun tashqi qiymatlarni validatsiya qilish kerak.
Masalan:
Endi:
deb tekshirish mumkin.
Status(99) uchun:
natijasi:
bo'ladi.
Har doim diapazon tekshiruvi yetarlimi?
Quyidagi:
usuli konstantalar ketma-ket bo'lganda yaxshi ishlaydi.
Masalan:
Lekin qiymatlar:
kabi bo'lsa, diapazon tekshiruvi noto'g'ri bo'lishi mumkin.
Bunday holatda switch ishlatish yaxshiroq:
func (s Status) Valid() bool {
switch s {
case StatusUnknown,
StatusPending,
StatusProcessing,
StatusCompleted:
return true
default:
return false
}
}
Bu usul faqat haqiqatan e'lon qilingan qiymatlarni qabul qiladi.
iota va tashqi formatlar
iota ishlatishda yana bir muhim xavf bor.
Faraz qilamiz:
qiymatlar:
bo'ladi.
Endi bu sonlarni database'ga yozdik deb tasavvur qilamiz.
Masalan:
Keyinchalik kodga yangi holat qo'shdik:
Endi qiymatlar:
bo'lib qoldi.
Oldingi database'dagi:
qiymati avval:
edi.
Yangi kodda esa:
bo'lib qoldi.
Bu juda jiddiy xatoga olib kelishi mumkin.
Shuning uchun iota qiymatlari tashqi tizim bilan bog'langan bo'lsa, ehtiyot bo'lish kerak.
Bunga quyidagilar kiradi:
- database;
- public API;
- protobufga o'xshash protokol;
- fayl formati;
- message broker;
- boshqa servis bilan kelishilgan kodlar.
Bunday holatda ikki xil xavfsizroq yondashuv bor.
Faqat oxiriga yangi qiymat qo'shish
Masalan:
Bunda eski qiymatlar o'zgarmaydi.
Aniq sonlarni yozish
Agar kodlar tashqi shartnoma bo'lsa, yanada aniqroq usul:
const (
StatusUnknown Status = 0
StatusPending Status = 10
StatusProcessing Status = 20
StatusCompleted Status = 30
)
Endi yangi qiymat qo'shish eski qiymatlarni avtomatik siljitmaydi.
Chuqurlashtirish: bit bayroqlar
Bit bayroqlar bir qiymatda bir nechta mustaqil holatni saqlash kerak bo‘lganda ishlatiladi. Boshlang‘ich bosqichda oddiy iota ketma-ketligini tushunish yetarli; ushbu bo‘limga keyinroq qaytishingiz mumkin.
iota faqat oddiy enumga o'xshash ketma-ketlik yaratish uchun emas.
U bit flag, ya'ni bit bayroqlar yaratishda ham juda qulay.
Masalan, foydalanuvchida quyidagi ruxsatlar bo'lsin:
- o'qish;
- yozish;
- o'chirish.
Oddiy enumda:
qilish mumkin.
Lekin bitta foydalanuvchida bir vaqtning o'zida bir nechta ruxsat bo'lishi kerak.
Masalan:
Bunday holatda bitmask ishlatish mumkin.
type Permission uint8
const (
PermissionRead Permission = 1 << iota
PermissionWrite
PermissionDelete
)
Bu yerda qiymatlar:
bo'ladi.
Nega?
Birinchi qator:
uchun:
Demak:
Binary ko'rinishda:
Keyingi qator:
Demak:
Binary:
Keyingi:
Binary:
Muhim tomoni — har bir qiymatda alohida bit yoqilgan.
Bit bayroqlarni birlashtirish
Bit flaglarni:
bitwise OR operatori yordamida birlashtirish mumkin.
Masalan:
Binary ko'rinishda:
| ishlatilganda:
hosil bo'ladi.
Bu decimal ko'rinishda:
Demak:
Lekin bu 3 oddiy ma'noda uchinchi enum qiymati emas.
Uning ichida ikkita bayroq mavjud:
Bayroq mavjudligini tekshirish
Masalan, qiymatda PermissionRead mavjudligini tekshirmoqchimiz.
Buning uchun:
ishlatiladi.
Masalan:
Agar:
bo'lsa:
natija:
bo'ladi.
Lekin:
natija:
bo'ladi.
Bit flaglar quyidagi holatlarda qulay:
- permissionlar;
- feature flaglar;
- notification sozlamalari;
- fayl rejimlari;
- protokol flaglari;
- bir nechta mustaqil
true/falseholatni bitta son ichida saqlash.
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)
}
Birinchi qatorda:
yozilgan.
Bu qatorda:
Demak:
Keyingi qatorda alohida ifoda yozilmagan:
Go oldingi:
ifodasini takrorlaydi.
Bu qatorda:
Shuning uchun:
Shu tartibda:
bo'ladi.
Shuning uchun:
natijasi:
bo'ladi.
Bu usul 0 qiymatini hafta kuni sifatida ishlatmaslik kerak bo'lgan vaziyatlarda qulay.
Shuningdek, foydalanuvchi ko'radigan yoki boshqa tizimdagi:
formatga moslashishni osonlashtirishi mumkin.
2. Nol qiymatni noma'lum holat uchun saqlash
Bu misolda turning zero value qiymati 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)
}
Dastlab:
deb o'zgaruvchi yaratildi.
Unga qiymat berilmagan.
DeliveryStatus int asosidagi tur bo'lgani uchun uning zero value qiymati:
bo'ladi.
Bizning konstantalarimizda:
ham:
ga teng.
Shuning uchun:
natijasi:
bo'ladi.
Bu yaxshi dizayn.
Chunki hali delivery holati aniq belgilanmagan bo'lsa:
deb tushunish mumkin.
Keyin:
deb haqiqiy holat berildi.
Qiymatlar:
bo'ladi.
Shuning uchun:
natijasi:
bo'ladi.
Bu yondashuvda haqiqiy biznes holatlari 1 dan boshlanadi, 0 esa "hali noma'lum" degan ma'noda ishlatiladi.
3. Keraksiz birinchi qiymatni tashlab ketish
Bu misolda _ yordamida birinchi iota qiymati ishlatilmaydi.
package main
import "fmt"
type Priority int
const (
_ Priority = iota
PriorityLow
PriorityMedium
PriorityHigh
)
func main() {
fmt.Println(
PriorityLow,
PriorityMedium,
PriorityHigh,
)
}
Birinchi qatorda:
iota:
ga teng.
Lekin qiymat:
blank identifieriga berilgan.
Shuning uchun bu qiymat uchun alohida konstanta nomi mavjud emas.
Keyingi qatorda:
Demak:
Keyingi:
va:
bo'ladi.
Natija:
Bu usul 0 haqiqiy qiymat bo'lmasligi kerak bo'lgan holatlarda qulay.
Masalan, 0:
degan yashirin holat sifatida qolishi mumkin.
4. Qiymatlarni o'n qadam bilan oshirish
iota formula ichida ishlatilishi mumkinligini ko'rgan edik.
Quyidagi misolda kodlar:
ko'rinishida yaratiladi.
package main
import "fmt"
type DepartmentCode int
const (
DepartmentSales DepartmentCode = (iota + 1) * 10
DepartmentSupport
DepartmentWarehouse
)
func main() {
fmt.Println(
DepartmentSales,
DepartmentSupport,
DepartmentWarehouse,
)
}
Birinchi qatorda:
formula ishlatilgan.
Bu qatorda:
Demak:
Shuning uchun:
Keyingi qator uchun:
Demak:
Shuning uchun:
Keyingi:
Demak:
Natija:
Bu usul kodlar orasida joy qoldirish kerak bo'lganda ishlatilishi mumkin.
Lekin agar bu qiymatlar database yoki tashqi API bilan doimiy shartnoma bo'lsa, iota o'rniga aniq son yozish ko'pincha xavfsizroq.
5. Bir satrda bog'liq qiymatlar yaratish
Bitta ConstSpec satrida bir nechta konstanta e'lon qilish mumkin.
Bu qatordagi barcha iotalar bir xil qiymatga ega bo'ladi.
Masalan:
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)
}
Birinchi qatorda:
iota:
ga teng.
Ikkala ifodadagi iota ham bir xil:
Shuning uchun:
Natija:
Keyingi qatorda ifoda yozilmagan:
Go oldingi ikkita ifodani takrorlaydi.
Bu qatorda:
Shuning uchun:
Keyingi qatorda:
Natija:
Demak, uchta diapazon hosil bo'ladi:
Bu misol bitta qatorda bir nechta iota ishlatilganda ular o'sha qator uchun bir xil qiymat olishini ko'rsatadi.
6. Har bir const guruhida qayta boshlash
Quyidagi misol iota yangi const blokida qaytadan 0 bo'lishini 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 const guruhida:
qiymatlar:
bo'ladi.
Keyin yangi:
guruhi ochildi.
Bu yerda iota:
dan davom etmaydi.
U yana:
dan boshlanadi.
Shuning uchun:
bo'ladi.
Natija:
Har bir alohida const guruhi o'z iota hisobiga ega.
Bu turli enumga o'xshash guruhlarning bir-biriga ta'sir qilmasligini ta'minlaydi.
7. Fayl ruxsatlarini birlashtirish
Bu misolda iota bit flag yaratish uchun ishlatiladi.
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)
}
Avval qiymatlarni hisoblaymiz.
Birinchi:
Bu yerda:
Demak:
Shuning uchun:
Binary:
Keyingi:
Binary:
Keyingi:
Binary:
Endi:
deyapmiz.
Binary:
Natijada:
Lekin bu 3 ichida ikkita mustaqil flag mavjud.
Keyin:
tekshirilmoqda.
CanRead biti yoqilganligi sabab natija:
bo'ladi.
Keyin:
tekshiriladi.
CanExecute biti yoqilmagan.
Shuning uchun natija:
bo'ladi.
Bu yondashuv bitta qiymatda bir nechta mustaqil ruxsatni saqlash imkonini beradi.
8. Bayroqni qiymatdan olib tashlash
Bit flagni faqat qo'shish emas, o'chirish ham mumkin.
Buning uchun Go'da:
operatori mavjud.
U bit clear, ya'ni ma'lum bitlarni tozalash uchun ishlatiladi.
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)
}
Avval qiymatlar:
bo'ladi.
Binary:
Keyin:
uchala flag ham birlashtiriladi:
Demak, boshida uchala notification turi yoqilgan.
Keyin:
deb yozilgan.
Bu:
NotifySMSga tegishli bitni tozalab tashla
degan ma'noni anglatadi.
Natijada:
dan:
qoladi.
Demak:
Shuning uchun:
natija:
natija:
va:
natija:
bo'ladi.
Natijalar:
9. Enum qiymatlarini matnga aylantirish
Son ko'rinishidagi status foydalanuvchiga yoki logga chiqarilganda tushunarsiz bo'lishi mumkin.
Shuning uchun unga matn qaytaradigan metod yozish mumkin.
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())
}
Qiymatlar:
bo'ladi.
Keyin:
chaqirilmoqda.
Metod:
qatoriga tushadi.
Natija:
bo'ladi.
Keyingi:
juda muhim misol.
20 e'lon qilingan konstantalar ichida yo'q.
Lekin Go:
konvertatsiyasiga ruxsat beradi.
Shuning uchun switch ichidagi hech bir asosiy case mos kelmaydi va:
ishlaydi.
Natija:
bo'ladi.
Bu yana bir bor Go'dagi enumga o'xshash tur yopiq qiymatlar to'plami emasligini ko'rsatadi.
Label() metodini ko'proq foydalanuvchi interfeysi uchun ishlatish mumkin.
Agar log va debugging uchun noma'lum sonning o'zini ham ko'rish kerak bo'lsa:
kabi yozish foydaliroq bo'lishi mumkin.
10. Tashqi format uchun aniq kodlarni saqlash
Har doim iota ishlatish shart emas.
Ayniqsa konstantalarning sonli qiymati tashqi tizim bilan kelishilgan bo'lsa, aniq sonlarni yozish xavfsizroq.
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 yerda:
va:
qiymatlari qo'lda aniq belgilangan.
Masalan, bu qiymatlar boshqa API bilan kelishilgan deb tasavvur qilamiz:
Bunday vaziyatda:
ishlatish xavfliroq bo'lishi mumkin.
Chunki yangi konstanta o'rtaga qo'shilsa, undan keyingi iota qiymatlari siljishi mumkin.
Aniq sonlar bilan:
const (
PaymentCreated PaymentCode = 100
PaymentApproved PaymentCode = 200
PaymentRejected PaymentCode = 400
)
yozilganda esa konstantalarni qayta tartiblash yoki orasiga yangi qiymat qo'shish mavjud kodlarni avtomatik o'zgartirmaydi.
Masalan:
const (
PaymentCreated PaymentCode = 100
PaymentPending PaymentCode = 150
PaymentApproved PaymentCode = 200
PaymentRejected PaymentCode = 400
)
deb yangi holat qo'shsak ham:
o'zgarishsiz qoladi.
Bu ayniqsa:
- public API;
- database;
- boshqa servis bilan integratsiya;
- message broker;
- fayl formati;
- uzoq vaqt saqlanadigan ma'lumot;
uchun muhim.
Shuning uchun iotani shunchaki kodni qisqartirish uchun ishlatishdan oldin sonlarning o'zi tashqi ma'no kasb etadimi yoki yo'qmi, shuni hisobga olish kerak.