Go’da modullar va paketlar
Go loyihasida paket kodni bo‘limlarga ajratadi, modul esa shu paketlarni versiyalash va tarqatish chegarasini belgilaydi. Bu farqni bilish import yo‘llarini to‘g‘ri tuzish va dependencylarni boshqarish uchun kerak.
Paket nima?
Paket — odatda bitta katalogda joylashgan va bir xil package nomiga ega Go fayllari to‘plami. Paket kompilyatsiya, nomlar sohasi va kodni qayta ishlatish birligidir.
Asosiy qoidalar:
- har bir
.gofaylpackage <nom>qatori bilan boshlanadi; - bitta katalogdagi oddiy
.gofayllar odatda bitta paketga tegishli bo‘ladi; - import qilinadigan nom paket ichida emas, paketlar orasida yagona bo‘lishi kerak;
package mainvafunc main()birga bajariladigan dastur kirish nuqtasini hosil qiladi.
Test fayllari bundan alohida holat: ular shu paket nomidan yoki _test qo‘shimchali tashqi test paketidan foydalanishi mumkin.
main paketi
Quyidagi to‘liq dastur bajariladigan paket yaratadi:
Natija:
package main kompilyatorga bajariladigan dastur yaratilishini bildiradi. main() esa dastur boshlanadigan funksiya. main() boshqa paketda yozilsa, u oddiy nom bo‘lib qoladi va kirish nuqtasi hisoblanmaydi.
Masalan, fayl package yangi_nom bilan boshlansa, uni buyruq sifatida ishga tushirib bo‘lmaydi:
Info
Kutubxona paketida main() bo‘lishi shart emas. U boshqa paketlar import qiladigan funksiyalar, turlar va o‘zgaruvchilarni taqdim etadi.
Modul nima?
Modul — go.mod fayli bilan belgilangan paketlar to‘plami. Modul yo‘li uning ichidagi paketlar import yo‘lining boshlanishi bo‘ladi.
Yangi loyiha yaratamiz:
Natijada taxminan quyidagi fayl yaratiladi:
module direktivasi modulning kanonik yo‘lini beradi. go direktivasi modul semantikasi va qo‘llanadigan til versiyasi uchun eng kichik talabni ifodalaydi; u kompyuterga Go’ni o‘rnatmaydi. Toolchain yaratgan aniq qiymat muhitga bog‘liq.
Lokal paket yaratish
Modul ichida kichik hisob paketini tuzamiz:
hisob/hisob.go:
package hisob
func Qosh(a, b int) int {
return a + b
}
func Kvadrat(n int) int {
return n * n
}
func ayir(a, b int) int {
return a - b
}
main.go:
package main
import (
"fmt"
"example.com/mening-loyiham/hisob"
)
func main() {
fmt.Println(hisob.Kvadrat(3))
fmt.Println(hisob.Qosh(3, 2))
}
Loyiha ildizida dasturni ishga tushiring:
Natija:
Import yo‘li example.com/mening-loyiham modul yo‘li va /hisob katalogidan tuzildi. Go importda fayl nomini emas, paket joylashgan katalog yo‘lini ishlatadi. go run . esa joriy katalogdagi main paketini build qilib ishga tushiradi.
Kvadrat uchun math.Pow kerak emas. Butun sonni o‘ziga ko‘paytirish aniqroq va float64ga ortiqcha konvertatsiyani chetlab o‘tadi. Juda katta int qiymatlarda ko‘paytirish overflow qilishi mumkin; bu misolda kichik qiymat ishlatilgan.
Eksport qilinadigan nomlar
Go’da identifikator bosh harf bilan boshlansa, u paketdan eksport qilinadi. Qosh va Kvadrat boshqa paketdan chaqiriladi. Kichik harf bilan boshlangan ayir esa faqat hisob paketi ichida ko‘rinadi.
Quyidagi chaqiruv kompilyatsiya xatosi beradi:
Xato mazmuni hisob.ayir eksport qilinmaganini bildiradi. Faqat nomni katta harf bilan boshlash yetarli emas: eksport qilingan API tushunarli nom, aniq vazifa va hujjatga ham ega bo‘lishi kerak.
Paket nomini odatda qisqa, kichik harfli va birlik shaklida tanlang: http, json, user. utils, common yoki helpers kabi umumiy nomlar paket mas’uliyatini yashirib qo‘yishi mumkin.
Import qanday topiladi?
Go import yo‘lini uch qism orqali tushunadi:
- joriy modul yo‘li
go.moddan olinadi; - modul ichidagi qolgan qism katalogni ko‘rsatadi;
- tashqi modul kerak bo‘lsa, uning versiyasi modul grafigidan tanlanadi.
Import yo‘li va paket nomi ko‘pincha katalog oxiri bilan bir xil, lekin bu majburiy emas. Masalan, paket boshqa nom e’lon qilsa, kodda aynan e’lon qilingan nom ishlatiladi. Tushunarlilik uchun ularni bir xil saqlash ma’qul.
Nomlar to‘qnashsa, importga lokal nom berish mumkin:
Bunda paket hisoblash.Qosh(...) shaklida chaqiriladi. Aliasni faqat nomlar to‘qnashuvi yoki tushunarlilik uchun ishlating.
Modul fayllari va dependency grafigi
go.modda quyidagi direktivalar uchrashi mumkin:
module— joriy modul yo‘li;go— modulning Go versiyasi talabi;require— dependency modul va tanlangan versiya;replace— modul manbasini boshqa yo‘l yoki versiyaga vaqtincha almashtirish;exclude— ma’lum versiyani tanlashdan chiqarish.
replace lokal ishlab chiqishda qulay, masalan:
Warning
Lokal katalogga yozilgan replace boshqa kompyuterda ishlamasligi mumkin. Uni commit qilishdan oldin jamoa va CI muhiti shu yo‘lni topa olishini tekshiring.
go.sum yuklangan modullar uchun nazorat summalarini saqlaydi. U lock-faylning aynan o‘zi emas: versiya tanlovi go.mod va modul grafigi orqali amalga oshadi, go.sum esa kontent yaxlitligini tekshirishga yordam beradi.
Foydali buyruqlar:
go mod tidy importlarga qarab go.mod va go.sumni tartiblaydi. go list -m all build ro‘yxatini, go mod graph modul bog‘lanishlarini ko‘rsatadi. go mod download dependencylarni keshga oldindan yuklaydi; odatiy build ham kerakli modullarni avtomatik yuklay oladi.
Versiya tanlashning muhim qoidalari
Go bir modul yo‘li uchun dependencylar talab qilgan versiyalar orasidan minimal talablarni qanoatlantiradigan build ro‘yxatini tuzadi. Natijada bir xil modul yo‘lining ikki versiyasi odatda bitta buildda yonma-yon tanlanmaydi.
v2 va undan katta asosiy versiyalar odatda modul hamda import yo‘liga /v2 kabi qo‘shimcha oladi:
Shu sabab example.com/lib va example.com/lib/v2 Go uchun ikki xil modul yo‘lidir. Bu katta API o‘zgarishini eski foydalanuvchilarga majburan yuklamaslikka yordam beradi.
internal paketlar
Modul ichidagi ayrim paketlarni tashqi foydalanuvchilardan yashirish uchun katalogni internal deb nomlash mumkin:
Go internal katalogidagi paketni faqat uning ruxsat etilgan ota daraxti ichidagi kod import qilishiga yo‘l qo‘yadi. Bu katta loyihada ommaviy API va ichki implementatsiya chegarasini kompilyator darajasida saqlaydi.
Keng tarqalgan xatolar
Nisbiy import ishlatish
Modul rejimida ./hisob kabi import yozmang. To‘liq modul yo‘lidan foydalaning:
Import cycle yaratish
a paketi bni, b esa yana ani import qilsa, Go dasturni kompilyatsiya qilmaydi. Umumiy turlarni uchinchi kichik paketga ajratish yoki dependency yo‘nalishini qayta loyihalash kerak.
Faylni alohida ishga tushirish
Paket bir nechta fayldan iborat bo‘lsa, go run main.go boshqa fayllarni chetda qoldirishi mumkin. Modul ildizidagi main paketi uchun ko‘pincha go run . to‘g‘ri tanlovdir.
Har katalogga alohida modul yaratish
Har bir paketga go.mod kerak emas. Odatda bitta repozitoriydagi o‘zaro bog‘liq paketlar bitta modul ichida bo‘ladi. Alohida versiyalash va mustaqil release zarur bo‘lgandagina bir nechta modulni ko‘rib chiqing.
Interviewda nimalarga e’tibor beriladi?
- paket kompilyatsiya va nomlar sohasi birligi, modul esa versiyalash birligi;
- eksport katta harf bilan belgilanadi, ammo bu faqat paket chegarasiga taalluqli;
go.modversiya talablarini,go.sumesa modul kontentining nazorat summalarini saqlaydi;- import cycle taqiqlangan;
v2+modul yo‘li odatda asosiy versiyani o‘z ichiga oladi.
Xulosa
Paket kodni mantiqiy qismlarga ajratadi. Modul esa paketlarning import yo‘li, dependencylari va versiyalash chegarasini belgilaydi. Lokal paket importida modul yo‘li bilan katalog yo‘lini birlashtiring, ommaviy API uchun eksport qoidalariga amal qiling va modul fayllarini Git’da saqlang.
Keyingi darsda modulga tashqi kutubxona qo‘shish, undan keyin esa eksport qilinadigan API uchun Go dokumentatsiyasini yozishni ko‘ramiz.