Tarkibga o'tish

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 .go fayl package <nom> qatori bilan boshlanadi;
  • bitta katalogdagi oddiy .go fayllar odatda bitta paketga tegishli bo‘ladi;
  • import qilinadigan nom paket ichida emas, paketlar orasida yagona bo‘lishi kerak;
  • package main va func 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:

main.go
package main

import "fmt"

func main() {
    fmt.Println("Go paketi bilan ishlash!")
}
go run main.go

Natija:

Go paketi bilan ishlash!

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:

package command-line-arguments is not a main package

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:

mkdir mening-loyiham
cd mening-loyiham
go mod init example.com/mening-loyiham

Natijada taxminan quyidagi fayl yaratiladi:

go.mod
module example.com/mening-loyiham

go 1.xx

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:

Loyiha strukturasi
mening-loyiham/
├── go.mod
├── main.go
└── hisob/
    └── hisob.go

hisob/hisob.go:

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:

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:

go run .

Natija:

9
5

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:

// Bu kod boshqa paket ichida kompilyatsiya bo‘lmaydi:
// fmt.Println(hisob.ayir(5, 2))

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:

  1. joriy modul yo‘li go.moddan olinadi;
  2. modul ichidagi qolgan qism katalogni ko‘rsatadi;
  3. 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:

import hisoblash "example.com/mening-loyiham/hisob"

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:

replace example.com/shared => ../shared

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
go list -m all
go mod graph
go mod download

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:

import "example.com/lib/v2/client"

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:

mening-loyiham/
├── go.mod
├── internal/
│   └── config/
└── main.go

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 "example.com/mening-loyiham/hisob"

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.mod versiya talablarini, go.sum esa 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.