Go’da asosiy ma'lumot turlari
Ma'lumot turi qiymat nimani ifodalashini va u bilan qanday amallar bajarish mumkinligini belgilaydi.
Masalan:
int— butun sonlarni;string— matnni;bool—trueyokifalseko‘rinishidagi mantiqiy holatni
ifodalaydi.
Tasavvur qiling, dastur foydalanuvchining ismi, yoshi va tizimga kirgan yoki kirmaganini saqlashi kerak. Bu qiymatlarning vazifasi bir-biridan farq qiladi. Shuning uchun ularning turlari ham boshqa bo‘ladi:
| main.go | |
|---|---|
Natija:
Bu yerda:
ism— matn, shuning uchun uning turistring;yosh— butun son, shuning uchun uning turiint;tizimgaKirdi— ha yoki yo‘q ko‘rinishidagi holat, shuning uchun uning turibool.
Turlar faqat qiymat qanday saqlanishini emas, u bilan qanday amallar bajarish mumkinligini ham belgilaydi.
Masalan, yosh bilan arifmetik amal bajarish mumkin:
ism esa matn sifatida ishlatiladi:
tizimgaKirdi kabi bool qiymat esa shartni tekshirishda foydali:
Ma'lumot turi nima uchun kerak?
Go — statik turli dasturlash tili. Bu degani, har bir o‘zgaruvchining turi kod kompilyatsiya qilinayotgan paytda ma'lum bo‘ladi.
Bu xususiyat kompilyatorga ko‘plab noto‘g‘ri amallarni dastur ishga tushishidan oldin aniqlashga yordam beradi.
Masalan, butun son saqlash uchun yaratilgan o‘zgaruvchiga keyin matn qiymatini berib bo‘lmaydi:
yosh o‘zgaruvchisi int sifatida e'lon qilingan. Shu sababli unga "yigirma besh" kabi string qiymatni berishga urinish compile time xatosiga olib keladi.
Go ko‘p hollarda turni boshlang‘ich qiymatga qarab o‘zi ham aniqlay oladi:
Bu yerda tur nomlarini qo‘lda yozmadik. Lekin o‘zgaruvchilar baribir aniq turga ega:
"Ali"matn literali bo‘lgani uchunism—string;25butun son literali bo‘lgani uchunyosh—int;19.5kasrli son literali bo‘lgani uchunnarx—float64.
Demak, := ishlatilgani o‘zgaruvchining turi yo‘q degani emas. Kompilyator turini boshlang‘ich qiymatdan aniqlaydi.
O‘zgaruvchining turini %T formatlash belgisi yordamida ko‘rish mumkin:
| main.go | |
|---|---|
Natija:
Bu yerda:
%v— qiymatni odatiy ko‘rinishda chiqaradi;%T— qiymatning Go’dagi turini chiqaradi.
Bu usul ayniqsa Go qaysi turni avtomatik tanlaganini tekshirishda qulay.
Butun sonlar
Butun sonlarda kasr qismi bo‘lmaydi.
Masalan:
Kundalik hisob-kitoblarda ko‘pincha int turi ishlatiladi:
Oxirgi qatorda tur alohida yozilmagan:
Go boshlang‘ich qiymatga qarab bu o‘zgaruvchini int deb aniqlaydi.
int turi platforma arxitekturasiga qarab 32 yoki 64 bit o‘lchamga ega bo‘ladi. Amalda oddiy hisoblar, yosh, mahsulotlar soni, indekslar va sanagichlar uchun odatda int tanlanadi.
Aniq o‘lchamdagi ishorali sonlar
Ba'zan turning aynan necha bit bo‘lishi muhim. Bunday holatda int8, int16, int32 va int64 turlaridan foydalanish mumkin.
Ular ishorali, ya'ni signed turlardir. Shuning uchun musbat sonlar bilan birga manfiy sonlar va nolni ham saqlay oladi.
| Tur | O‘lchami | Qiymatlar oralig‘i |
|---|---|---|
int8 |
8 bit | -128 dan 127 gacha |
int16 |
16 bit | -32 768 dan 32 767 gacha |
int32 |
32 bit | -2 147 483 648 dan 2 147 483 647 gacha |
int64 |
64 bit | -9 223 372 036 854 775 808 dan 9 223 372 036 854 775 807 gacha |
Masalan, int8 faqat 256 ta turli qiymatni ifodalay oladi:
Shu sababli 128 qiymati int8 oralig‘iga sig‘maydi.
Ishorasiz butun sonlar
Go’da unsigned, ya'ni ishorasiz butun son turlari ham mavjud.
Ular manfiy qiymatlarni saqlamaydi:
| Tur | O‘lchami | Qiymatlar oralig‘i |
|---|---|---|
uint8 |
8 bit | 0 dan 255 gacha |
uint16 |
16 bit | 0 dan 65 535 gacha |
uint32 |
32 bit | 0 dan 4 294 967 295 gacha |
uint64 |
64 bit | 0 dan 18 446 744 073 709 551 615 gacha |
Masalan, uint8 uchun:
oraliq mavjud.
uint turi ham int kabi platforma arxitekturasiga qarab 32 yoki 64 bit bo‘ladi.
Oddiy hisob-kitoblarda ko‘pincha int qulayroq. Sababi Go turli son turlarini avtomatik aralashtirmaydi.
Masalan, int bilan uint qiymatini to‘g‘ridan-to‘g‘ri qo‘shib bo‘lmaydi:
Bunday holatda turlardan birini aniq konvertatsiya qilish kerak.
Warning
Tur sig‘dira oladigan qiymatlar oralig‘idan chiqish overflow deb ataladi.
Son uchun juda kichik tur tanlansa, qiymat unga sig‘masligi mumkin. Shuning uchun ma'lumotning mumkin bo‘lgan eng katta va eng kichik qiymatini hisobga olib tur tanlash muhim.
Masalan:
Bu kod kompilyatsiyadan o‘tmaydi. Sababi int8 uchun eng katta qiymat 127, lekin biz 128 bermoqdamiz.
Natija taxminan quyidagicha bo‘ladi:
.\main.go:6:17: cannot use 128 (untyped int constant)
as int8 value in variable declaration (overflows)
Kompilyator bu xatoni dastur ishga tushmasidan oldin aniqlaydi.
Bu yerda 128 hali aniq bir integer turiga bog‘lanmagan constant. Lekin uni int8 o‘zgaruvchisiga joylashtirish so‘ralganda kompilyator qiymat oralig‘ini tekshiradi va u sig‘masligini ko‘radi.
Kasrli sonlar
Kasr qismi mavjud sonlar uchun Go’da float32 va float64 turlari ishlatiladi:
Ularning asosiy farqlaridan biri aniqlik va xotira hajmidir:
| Tur | O‘lchami | Taxminiy aniqligi |
|---|---|---|
float32 |
32 bit | 6–7 ta o‘nlik raqam |
float64 |
64 bit | 15–16 ta o‘nlik raqam |
Go kasrli son literalining turini avtomatik aniqlaganda odatda float64 tanlaydi:
Bu yerda narx turi float64 bo‘ladi.
Shu sababli umumiy hisob-kitoblarda float64 ko‘proq uchraydi.
Masalan:
| main.go | |
|---|---|
Hisob quyidagicha bajariladi:
Natija:
%.2f formatlash belgisi kasrli sonni verguldan keyin ikki xona bilan chiqaradi.
Qiymatning o‘zi 37.5 bo‘lsa ham, ekranga:
ko‘rinishida chiqariladi.
Info
float32 va float64 ayrim o‘nli kasrlarni ikkilik formatda mutlaqo aniq saqlay olmaydi.
Masalan, `0.1` kabi qiymat ichki xotirada unga juda yaqin bo‘lgan son sifatida saqlanishi mumkin. Ko‘pchilik oddiy hisoblarda bu muammo sezilmaydi, lekin pul bilan ishlaganda kichik yaxlitlash xatolari muhim bo‘lishi mumkin.
Pul qiymatlarini saqlashda ko‘pincha eng kichik pul birligidan foydalanish qulay. Masalan, `12.50` qiymatni `1250` kabi butun son ko‘rinishida saqlash mumkin. Bu holatda hisob-kitob integer qiymatlar bilan bajariladi.
Mantiqiy tur: bool
bool faqat ikki qiymatdan birini saqlaydi:
Bu tur ha yoki yo‘q ko‘rinishidagi holatlarni ifodalash uchun ishlatiladi.
Masalan:
Bu yerda:
faol—true, ya'ni foydalanuvchi faol;bloklangan—false, ya'ni foydalanuvchi bloklanmagan.
Taqqoslash operatorlarining natijasi ham bool turida bo‘ladi.
Masalan:
| main.go | |
|---|---|
Bu yerda quyidagi taqqoslash bajariladi:
Qiymatlarni qo‘yib ko‘rsak:
Bu shart rost. Shuning uchun:
bo‘ladi.
Natija:
Keyingi darslarda bool qiymatlarni if kabi shart operatorlari bilan ko‘p ishlatamiz.
Matn turi: string
string matn saqlash uchun ishlatiladi.
Texnik jihatdan string — baytlar ketma-ketligi. Odatda bu baytlar UTF-8 formatidagi matnni ifodalaydi.
String literal qo‘shtirnoq ichida yoziladi:
Bu yerda:
"Dilshod"— oddiy matn;"Go'ni o'rganamiz"— boshqa matn;""— uzunligi nol bo‘lgan bo‘sh string.
Ikki matnni + operatori yordamida birlashtirish mumkin:
| main.go | |
|---|---|
Birlashtirish jarayoni quyidagicha:
Natijada yangi string hosil bo‘ladi:
Go source code odatda UTF-8 formatida yoziladi. Stringlar esa baytlar ketma-ketligini saqlaydi. UTF-8 matn bilan ishlaganda o‘zbekcha harflar, emoji va boshqa Unicode belgilarini saqlash mumkin.
Lekin bu yerda muhim bir noziklik bor: bitta ko‘rinadigan Unicode belgi har doim bitta bayt degani emas.
Shuning uchun string bilan ishlaganda bayt soni va Unicode code point soni bir-biridan farq qilishi mumkin.
byte va rune
Go’da matn bilan ishlaganda byte va rune turlarini ko‘p uchratamiz.
byte — uint8 turining boshqa nomi:
U ko‘pincha bitta bayt qiymatini ifodalash uchun ishlatiladi.
Masalan:
rune esa int32 turining boshqa nomi:
U odatda bitta Unicode code pointni ifodalash uchun ishlatiladi.
Rune literal bittalik tirnoq ichida yoziladi:
Bu yerda "O" string emas. 'O' — bitta rune literal.
string uzunligini len() bilan olsak, Unicode belgilar soni emas, baytlar soni qaytadi.
Masalan:
| main.go | |
|---|---|
Natija:
Nega len(matn) 6 chiqardi?
Matn:
uchta ko‘rinadigan belgidan iborat:
Lekin UTF-8 formatida ularning bayt hajmi bir xil emas:
Jami:
Shuning uchun:
natijasi:
bo‘ladi.
Quyidagi ifoda esa:
stringni Unicode code pointlar ketma-ketligiga aylantiradi.
Natijada uchta rune hosil bo‘ladi:
Shuning uchun:
natijasi 3 bo‘ladi.
Bu farq Unicode matnlarni indekslash va uzunligini hisoblashda muhim. byte, rune va UTF-8 bilan ishlashni keyingi darslarda batafsil ko‘ramiz.
Kompleks sonlar
Go kompleks sonlar uchun ham alohida turlarga ega:
Kompleks son ikki qismdan tashkil topadi:
- haqiqiy qism;
- mavhum qism.
Masalan:
Bu qiymat matematik ko‘rinishda:
degan ma'noni anglatadi.
complex() funksiyasi ikkita qiymatni olib, kompleks son yaratadi:
Bu yerda:
Kompleks sonlar ilmiy, matematik va muhandislik hisoblarida ishlatiladi.
Oddiy web dasturlar, CLI dasturlar yoki kundalik biznes logikasida ular kam uchraydi. Shu sababli hozircha ularning mavjudligini va asosiy vazifasini bilish yetarli.
Turlarni o‘zgartirish
Go son turlarini avtomatik ravishda bir-biriga o‘girmaydi.
Masalan, int va float64 alohida turlar hisoblanadi. Ularni bitta arifmetik ifodada ishlatish uchun kerakli qiymatni aniq konvertatsiya qilishimiz kerak.
Misol:
| main.go | |
|---|---|
Bu yerda:
int turida.
narx esa:
turida.
Quyidagicha yozish mumkin emas:
Sababi int va float64 turidagi qiymatlar to‘g‘ridan-to‘g‘ri ko‘paytirilmaydi.
Shuning uchun:
deb dona qiymatini hisob davomida float64ga konvertatsiya qilamiz.
Hisob:
Muhim jihat shundaki, konvertatsiya asl o‘zgaruvchining turini o‘zgartirmaydi.
Ya'ni:
hali ham int.
Faqat:
ifodasi yangi float64 qiymat hosil qiladi.
Kasrli sonni butun songa aylantirish ham mumkin:
Natijada:
bo‘ladi.
Bu yaxlitlash emas.
float64 qiymati intga konvertatsiya qilinganda kasr qismi tashlab yuboriladi va qiymat nol tomonga qisqartiriladi.
Masalan:
Demak, int(9.8) natijasi 10 bo‘lmaydi.
Agar haqiqiy yaxlitlash kerak bo‘lsa, buning uchun boshqa usullardan foydalaniladi.
Warning
Katta sonni kichik oraliqli turga runtime qiymati sifatida konvertatsiya qilish natijani o‘zgartirib yuborishi mumkin.
Masalan:
uint8 faqat:
oralig‘ini saqlaydi.
300 bu oraliqqa sig‘maydi. Konvertatsiyadan keyin yuqori bitlar tashlab yuboriladi va natija:
bo‘ladi.
Buni quyidagicha tasavvur qilish mumkin:
uint8 faqat pastki 8 bitni saqlay olgani uchun 44 qoladi.
Lekin constant uchun qoida boshqacha.
Masalan:
kompilyatsiyadan o‘tmaydi. Sababi compiler constant qiymat uint8 oralig‘iga sig‘masligini oldindan ko‘ra oladi.
Shuning uchun runtime qiymatni kichikroq turga konvertatsiya qilishdan oldin uning yangi tur oralig‘iga sig‘ishini tekshirish muhim.
Sonni matnga yoki matnni songa aylantirish oddiy son turlari orasidagi konvertatsiyadan farq qiladi.
Masalan:
uchun odatda strconv paketidan foydalaniladi.
Bu mavzuni keyingi darslarda, paketlar va ma'lumot kiritish bilan ishlaganda batafsil ko‘ramiz.
Nol qiymatlar
Go’da boshlang‘ich qiymat berilmagan o‘zgaruvchi tasodifiy qiymat olmaydi.
U avtomatik ravishda o‘z turining zero value, ya'ni nol qiymatini oladi.
Asosiy turlar uchun nol qiymatlar quyidagicha:
| Tur | Nol qiymat |
|---|---|
| butun va kasrli sonlar | 0 |
| kompleks sonlar | 0+0i |
bool |
false |
string |
"" |
Masalan:
| main.go | |
|---|---|
Bu o‘zgaruvchilarning hech biriga boshlang‘ich qiymat bermadik:
Shunga qaramay, ular ma'lum qiymatlarga ega:
Natija:
Bu Go’ning muhim xususiyatlaridan biri.
Masalan:
yozsak, faol avtomatik ravishda false bo‘ladi.
Yoki:
yozsak, xabar nil emas, bo‘sh string:
bo‘ladi.
Zero value tushunchasi keyingi mavzularda struct, pointer, slice, map va interface bilan ishlaganda ham muhim bo‘ladi.
Qaysi turni tanlash kerak?
Yangi boshlaganda quyidagi oddiy qoidalar yetarli:
- butun son uchun
int; - kasrli son uchun
float64; - matn uchun
string; - ha yoki yo‘q holati uchun
bool; - bitta Unicode code point uchun
rune.
Masalan:
yosh := 25 // int
narx := 19.99 // float64
ism := "Ali" // string
faol := true // bool
belgi := 'A' // rune
Aniq o‘lchamdagi int32, uint16 yoki float32 kabi turlarni esa bunga haqiqiy ehtiyoj bo‘lganda tanlash ma'qul.
Masalan:
- binary format bilan ishlaganda;
- network protocol aniq bit o‘lchamini talab qilganda;
- fayl formatida maydon hajmi qat'iy belgilangan bo‘lsa;
- tashqi API yoki database ustuni bilan aniq tur mosligi kerak bo‘lsa.
Array, slice, map, struct, pointer, function, interface va channel ham Go’dagi turlardir.
Ular oddiy int yoki stringdan murakkabroq vazifalarni bajaradi. Masalan:
- slice — qiymatlar ketma-ketligini saqlaydi;
- map — kalit va qiymat bog‘lanishini saqlaydi;
- struct — bir nechta fieldni bitta qiymatga birlashtiradi;
- pointer — boshqa qiymatning xotiradagi manziliga murojaat qiladi;
- function — funksiyaning o‘zi ham qiymat bo‘lishi mumkin;
- interface — turning qanday xatti-harakatga ega bo‘lishini ifodalaydi;
- channel — goroutinelar orasida qiymat uzatish uchun ishlatiladi.
Ularni keyingi qismlarda alohida ko‘rib chiqamiz.
Info
nil alohida ma'lumot turi emas.
U pointer, slice, map, channel, function va interface kabi ayrim turlarda qiymat yoki obyekt mavjud emasligini bildirish uchun ishlatiladigan maxsus qiymat.
Misollar
1. Butun son turining chegarasi
Bu misol int8 turi qaysi oraliqdagi sonlarni saqlay olishini ko‘rsatadi.
math paketida ayrim son turlarining minimal va maksimal qiymatlarini ifodalovchi constantlar mavjud:
Natija:
Demak, int8 turi:
oralig‘idagi qiymatlarni saqlaydi.
Masalan:
to‘g‘ri.
Lekin:
xato.
Agar bundan kattaroq yoki kichikroq qiymatlar kerak bo‘lsa, int16, int32, int64 yoki vazifaga mos boshqa tur tanlanadi.
Bu misol son turini tanlashda uning sig‘imini hisobga olish kerakligini ko‘rsatadi.
2. Ishorasiz butun son
Bu misol manfiy bo‘la olmaydigan kichik qiymatni uint8 turida saqlashni ko‘rsatadi:
Natija:
uint8 oralig‘i:
bo‘lgani uchun 255 bu turga sig‘adi.
Masalan:
RGB rang modelidagi rang kanalini ifodalash uchun tabiiy ko‘rinishi mumkin, chunki rang komponentlari ko‘pincha 0 dan 255 gacha bo‘ladi.
Lekin manfiy qiymatni to‘g‘ridan-to‘g‘ri constant sifatida berish mumkin emas:
Bu compile time xatosiga olib keladi.
Bu misol signed va unsigned integer turlarining asosiy farqini ko‘rsatadi.
3. Tur o‘zgartirish
Bu misol Go son turlarini yashirin ravishda aralashtirmasligini ko‘rsatadi:
package main
import "fmt"
func main() {
soni := 3
narx := 12.5
jami := float64(soni) * narx
fmt.Println(jami)
}
Bu yerda:
int turida.
esa float64 turida.
Shuning uchun:
orqali soni qiymatini hisob uchun float64ga o‘tkazamiz.
Keyin:
Natija:
Agar konvertatsiya yozilmasa:
kompilyator int va float64 bir-biriga mos emasligini bildiradi.
Bu misol Go’da son turlari orasidagi konvertatsiya aniq yozilishi kerakligini ko‘rsatadi.
4. Butun songa o‘tkazishda kasr qismi
Bu misol float64 qiymatini intga konvertatsiya qilganda nima bo‘lishini ko‘rsatadi:
package main
import "fmt"
func main() {
musbat, manfiy := 8.9, -8.9
fmt.Println(int(musbat), int(manfiy))
}
Natija:
Bu yerda:
Kasr qismi tashlab yuborildi.
Muhim jihat: bu matematik yaxlitlash emas.
Masalan:
eng yaqin butun songa yaxlitlansa 9 bo‘lishi mumkin edi.
Lekin:
natijasi 8.
Manfiy qiymatda ham son nol tomonga qisqartiriladi:
natijasi:
bo‘ladi.
Bu misol floating-point sondan integer turiga konvertatsiya qilishning xatti-harakatini ko‘rsatadi.
5. byte turida belgi saqlash
Bu misol byte aslida uint8 uchun boshqa nom ekanini ko‘rsatadi:
package main
import "fmt"
func main() {
var belgi byte = 'G'
fmt.Printf("%d %c %T\n", belgi, belgi, belgi)
}
Natija:
Bu yerda 'G' rune literal.
G Unicode va ASCII jadvalida decimal ko‘rinishda:
qiymatiga ega.
U bytega sig‘gani uchun:
yozish mumkin.
Formatlash belgilariga qarasak:
Shuning uchun bitta qiymat uch xil ko‘rinishda chiqariladi:
byte — uint8 turining aliasi. Shu sababli %T natijada uint8ni ko‘rsatadi.
Bu tur binary ma'lumot, fayl, network ma'lumoti yoki UTF-8 stringning alohida baytlari bilan ishlashda ko‘p uchraydi.
6. rune bilan Unicode belgi
Bu misol bitta Unicode code pointni rune sifatida saqlashni ko‘rsatadi:
package main
import "fmt"
func main() {
belgi := '‘'
fmt.Printf("%c %U %T\n", belgi, belgi, belgi)
}
belgi qiymati bittalik tirnoq ichida yozilgan:
Shuning uchun u string emas, rune literal hisoblanadi.
rune esa int32 turining aliasi.
Formatlash belgilarining vazifasi:
Shuning uchun natija taxminan quyidagicha bo‘ladi:
Bu yerda:
— chap egri bittalik qo‘shtirnoqning Unicode code pointi.
Bu misol rune faqat ASCII belgilar uchun emas, Unicode belgilar bilan ishlash uchun ham mos ekanini ko‘rsatadi.
7. Ilmiy yozuvdagi kasrli son
Juda katta yoki juda kichik floating-point qiymatlarni ilmiy yozuvda yozish mumkin:
package main
import "fmt"
func main() {
yoruglikTezligi := 3e8
kichikQiymat := 1.5e-3
fmt.Println(yoruglikTezligi, kichikQiymat)
}
e yozuvi 10 ning darajasini bildiradi.
Masalan:
quyidagini anglatadi:
ya'ni:
1.5e-3 esa:
ya'ni:
degani.
Tur aniq yozilmagani uchun ikkala qiymat ham odatda float64 sifatida aniqlanadi:
Ilmiy hisoblarda bu yozuv juda katta yoki juda kichik sonlarni ancha ixcham ko‘rsatishga yordam beradi.
8. Xom matn literali
Go’da stringni oddiy qo‘shtirnoq bilan emas, teskari qo‘shtirnoq bilan ham yozish mumkin.
Bunday string raw string literal, ya'ni xom matn literali deyiladi:
Natija:
Oddiy stringda \ belgisi escape sequence boshlanishini bildirishi mumkin.
Masalan:
Bu yerda \n yangi qatorni bildiradi.
Raw string ichida esa \ o‘z holicha saqlanadi:
Shuning uchun Windows fayl yo‘llari yoki backslash ko‘p ishlatiladigan matnlarda raw string qulay bo‘lishi mumkin.
Raw string ko‘p qatorli matn uchun ham ishlatiladi:
Bu misol string literalni yozishning ikki xil usuli borligini ko‘rsatadi.
9. Kompleks son
Bu misol Go’da kompleks son yaratish va uning qismlarini alohida olishni ko‘rsatadi:
Quyidagi chaqiruv:
kompleks son yaratadi:
Bu yerda:
real() haqiqiy qismni oladi:
natijasi:
imag() esa mavhum qismni oladi:
natijasi:
Natija odatda quyidagiga o‘xshaydi:
Bu misol complex(), real() va imag() funksiyalarining asosiy vazifasini ko‘rsatadi.
10. Turini format orqali ko‘rish
Bu misol tashqi ko‘rinishi o‘xshash qiymatlar har xil turga ega bo‘lishi mumkinligini ko‘rsatadi:
package main
import "fmt"
func main() {
butun := 26
kasr := 26.5
matn := "26.5"
fmt.Printf("%T %T %T\n", butun, kasr, matn)
}
Bu yerda:
— int.
— float64.
— string.
26.5 va "26.5" ko‘zga o‘xshash ko‘rinadi, lekin Go uchun ular mutlaqo boshqa qiymatlar.
Birinchisi son:
Ikkinchisi esa belgilar ketma-ketligi:
%T yordamida ularning turini ko‘rsak:
natijasi chiqadi.
Bu misol qiymatning ekrandagi ko‘rinishi bilan uning Go’dagi turi bir xil tushuncha emasligini ko‘rsatadi.