Go dasturchisidan gofmt yo'q tilga o'tganda eng ko'p nimani sog'inishini so'rasangiz, halol javob odatda shunday bo'ladi: "tabulyatsiya yoki bo'sh joy haqida bahslashmaslikni". Go formatlash masalasini erta hal qildi va butunlay hal qildi, va shu bitta qaror kod ko'rib chiqishdagi butun bir turkum izohlarni hamda uslub qo'llanmasi bahslarini yo'q qiladi. Ushbu bobda Go kodini izchil va o'z-o'zini hujjatlaydigan holda saqlaydigan uchta vosita ko'rib chiqiladi: go fmt, go vet va go doc hamda pkg.go.dev ni oziqlantiradigan hujjat izohlari kelishuvlari.
gofmt (butun paketlar ustida ishlashini istasangiz, go fmt sifatida chaqiriladi) Go manba kodini tilning yagona kanonik uslubiga qayta yozadi: chekinish uchun tabulyatsiya, operatorlar atrofida izchil bo'sh joy, tekislangan struct maydonlari va import bloklari, oxirida ortiqcha bo'sh joy yo'q.
go fmt ./...
O'zgartirish mexanik va muhokamasiz, gap ham aynan shunda:
// oldin
package main
import "fmt"
import "strings"
func main(){
x:=5
if x>3{
fmt.Println("x is greater than 3")
}
}
// go fmt dan keyin
package main
import "fmt"
import "strings"
func main() {
x := 5
if x > 3 {
fmt.Println("x is greater than 3")
}
}
Aynan bitta qabul qilingan joylashuv bo'lgani uchun Go kod bazalaridagi diff'lar kichik va mazmunli bo'lib qoladi: faqat formatlashga oid o'zgarish hech qachon mantiq o'zgarishiga aralashib kelmaydi, chunki ifodalanadigan formatlash didi degan narsaning o'zi yo'q.
Har bir yetakchi muharrir saqlashda formatlashni qo'llab-quvvatlaydi (VS Code Go kengaytmasi va GoLand buni standart holda bajaradi; Vim va Emacs bunga mos ravishda vim-go va gofmt-before-save orqali erishadi), va bu sozlangach, siz go fmt ni qo'lda kamdan-kam ishga tushirasiz.
golang.org/x/tools modulidan chiqadigan hamroh vosita goimports gofmt qiladigan hamma narsani qiladi va qo'shimcha ravishda import blokingizni boshqaradi: siz murojaat qilgan, lekin import qilmagan paketlar uchun importlarni qo'shadi, endi ishlatilmaydiganlarini olib tashlaydi va standart kutubxonani uchinchi tomon paketlaridan alohida guruhlaydi:
go install golang.org/x/tools/cmd/goimports@latest
goimports -w .
// oldin
package main
func main() {
fmt.Println("Hello")
}
// goimports dan keyin
package main
import "fmt"
func main() {
fmt.Println("Hello")
}
Ko'pchilik muharrir integratsiyalari aynan shu sababdan oddiy gofmt o'rniga goimports ni ishga tushiradi — u import ifodalarini qo'lda boshqarishdagi kichik, ammo doimiy noqulaylikdan xalos qiladi.
Formatlash tashqi ko'rinish haqida bo'lsa, go vet to'g'rilik haqida. Bu statik tahlilchi bo'lib, muammosiz kompilyatsiya bo'ladigan, ammo deyarli aniq xato bo'lgan konstruksiyalarni qidiradi:
go vet ./...
Argumentining tipiga mos kelmaydigan format spetsifikatori (format verb) bilan yozilgan Printf chaqiruvi — klassik misol:
fmt.Printf("%s", 42) // vet: %s format spetsifikatori uchun 42 argumenti noto'g'ri tipda
Vet yana erishib bo'lmaydigan kodni, sintaksisi noto'g'ri struct teglarini, tasodifan noto'g'ri imzo (signature) bilan e'lon qilingan String() string metodini (bu fmt ning undan to'g'ri foydalanishiga xalaqit beradi), errors.New kabi chaqiruvlar natijasining o'zgaruvchiga olinmasdan tashlab yuborilishini, va eng muhimi — ichida sync.Mutex kabi sinxronizatsiya vositasi bor struct'larni qiymat bo'yicha (nusxalab) noto'g'ri uzatishni aniqlab beradi:
type S struct {
mu sync.Mutex
}
func bad(s S) { // vet: bad funksiyasi mutex qulfini qiymat bo'yicha nusxalayapti
s.mu.Lock()
// bu muteksning *nusxasini* qulflaydi — chaqiruvchining qulfiga tegilmaydi
}
Vet standart holda saralangan tekshiruvlar to'plamini ishga tushiradi; go vet -all to'liq to'plamni ishga tushiradi.
U tez ishlagani va deyarli xatosiz ogohlantirgani uchun, har bir CI/CD jarayonida
go buildvago testyonida doimiy ishga tushishi lozim.
go vet ./... || exit 1
Ko'pchilik muharrirlar uni gofmt bilan birga avtomatik ishga tushiradi va ogohlantirishlarni commit paytida emas, siz yozayotganda ko'rsatadi. Agar sizga vet ning standart tekshiruvlaridan ko'prog'i kerak bo'lsa — uslub kelishuvlari, ishlatilmagan parametrlar, kod bazangizga xos xatolarni boshqarish patternlari — hamjamiyat vositasi golangci-lint o'nlab qo'shimcha tahlilchini bitta sozlanadigan buyruq ortiga to'playdi, va ishlab chiqarishdagi ko'pchilik Go loyihalari uni CI'da ishlatadi; 50-bob uni boshqa statik tahlil va xavfsizlik vositalari bilan birga ko'rib chiqadi.
Go hujjatlari siz vikida yozadigan alohida artefakt emas — u to'g'ridan-to'g'ri paket e'lonlariga, eksport qilingan tiplarga va eksport qilingan funksiyalarga biriktirilgan izohlardan hosil qilinadi.
Bu shuni anglatadiki, yaxshi hujjat izohi yozish bilan yaxshi hujjat yozish — bitta ishning o'zi, va bu ataylab qilingan dizayn qarori: u hujjatni shu qadar arzon qiladiki, odamlar uni chindan yangilab turadi.
Paket izohi package ifodasidan bevosita yuqorida, paketning eng markaziy faylida turadi (agar aniq bitta kirish nuqtasi bo'lmasa, ko'pincha maxsus doc.go faylida):
// Package math asosiy matematik amallarni taqdim etadi.
//
// Bu paket butun sonlarni qo'shish, ayirish, ko'paytirish va
// bo'lish funksiyalarini o'z ichiga oladi.
package math
Funksiya, tip va metod izohlari xuddi shu kelishuvga amal qiladi — izoh bilan e'lon orasida bo'sh qator bo'lmaydi — va kuchli kelishuvga ko'ra hujjatlanayotgan nom bilan boshlanadi, shunda vositalar ham, o'quvchilar ham bir qatorlik xulosani mexanik tarzda ajratib ola oladi:
// Add ikkita butun sonning yig'indisini qaytaradi.
func Add(a, b int) int {
return a + b
}
// User tizimdagi foydalanuvchini ifodalaydi. Unda foydalanuvchining
// ID raqami, ismi va e-pochta manzili saqlanadi.
type User struct {
ID int
Name string
Email string
}
// String User ning satr ko'rinishini "Ism (e-pochta)" formatida
// qaytaradi.
func (u *User) String() string {
return fmt.Sprintf("%s (%s)", u.Name, u.Email)
}
// MaxRetries muvaffaqiyatsiz amaldan voz kechishdan oldin qilinadigan
// urinishlarning eng ko'p soni.
const MaxRetries = 3
O'zlashtirish foydali bo'lgan qisqa uslub ro'yxati: nom bilan boshlang (Add ... qaytaradi, Bu funksiya ... qo'shadi emas), parchalar emas, to'liq gaplar yozing, va imzodan allaqachon ko'rinib turgan narsani takrorlamang — ID id ni qaytaradi o'quvchiga u bilmagan hech narsani aytmaydi, ID foydalanuvchi yaratilganda berilgan noyob identifikatorni qaytaradi esa o'z o'rnini oqlaydi. Xatti-harakatida haqiqiy nozik jihat bor har qanday narsa uchun — noto'g'ri kirishda nima bo'lishi, slice argumenti saqlab qolinadimi yoki nusxalanadimi, metodni bir vaqtda chaqirish xavfsizmi — buni izohda aniq ayting, chunki imzoning o'zi buni ayta olmaydi.
godoc uslubidagi izohlar to'liq Markdown'siz ham kichik tuzilmani qo'llab-quvvatlaydi: bo'sh izoh qatori yangi abzas boshlaydi, tabulyatsiya bilan chekintirilgan qator esa oldindan formatlangan kod bloki sifatida qabul qilinadi:
// Parse kirish satrini tahlil qiladi va Result qaytaradi.
//
// Kirish "key=value" ko'rinishida bo'lishi shart. Tahlil
// muvaffaqiyatsiz bo'lsa, nil bo'lmagan xato qaytariladi.
//
// Misol:
//
// result, err := Parse("name=John")
// if err != nil {
// log.Fatal(err)
// }
func Parse(input string) (Result, error) { ... }
Ishga tushiriladigan misollar alohida eslatish foydali: _test.go faylidagi Example yoki ExampleFoo deb nomlangan, ichida // Output: izohi bor funksiya go test tomonidan kompilyatsiya qilinadi, bajariladi va tekshiriladi, hamda pkg.go.dev da jonli misol sifatida ko'rsatiladi.
Ular bir vaqtning o'zida hujjat ham, foydalanish namunasi ham, test ham — standart asboblar to'plamidagi eng nafis ko'p maqsadli kelishuvlardan biri.
pkg.go.dev ochiq import qilinadigan har qanday Go moduli uchun ko'rib chiqiladigan hujjatlarni avtomatik hosil qiladi, to'g'ridan-to'g'ri yuqorida tasvirlangan izohlardan — alohida nashr qadami ham, sozlanadigan hujjat joylashtirish xizmati ham yo'q. Modulda haqiqiy go.mod bo'lib, u go get orqali kamida bir marta olingach, sayt uni indekslaydi va paket haqida umumiy ma'lumotni, eksport qilingan belgilarning to'liq ro'yxatini, har bir funksiya bo'yicha hujjatni, ishga tushiriladigan misollarni hamda manba kodiga havolalarni ko'rsatadi.
Amaliy xulosa shuki, "yaxshi hujjat izohlari yozish" — bu yaxshi ochiq hujjatga ega bo'lishning butun strategiyasi.
Intizomli izohlardan va, chindan qiymat qo'shadigan joylarda, bir nechta Example funksiyasidan boshqa alohida sarmoya kerak emas. Lokal darajada, hali hech qayerda hech narsa nashr qilinmasdan oldin, go doc -http=:6060 o'z kompyuteringizdagi paketlar uchun xuddi shu ko'rinishni beradi.
// Package calculator asosiy arifmetik amallarni taqdim etadi.
package calculator
import "fmt"
// Add ikkita butun sonning yig'indisini qaytaradi.
func Add(a, b int) int {
return a + b
}
// Divide a ni b ga bo'ladi va natijani qaytaradi. Agar b nol
// bo'lsa, xato qaytaradi.
func Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
Shu kodga nisbatan go fmt, go vet va go doc ni ishga tushiring — natijada izchil formatlangan kod, xatolarsiz toza statik tahlil va ikki marta yozishingiz shart bo'lmagan hujjat hosil bo'ladi. Bu uch vositaning hech biri alohida olib qaraganda favqulodda yangilik emas — formatlovchi, linter, hujjat generatori barcha yetuk tillarda bor — ammo uchalasining ham Go bilan birga o'rnatilishi, yagona qoidalarga tayanishi va bir xil uslubda (go <buyruq>) chaqirilishi har qanday yangi Go loyihasini dastlabki daqiqalardanoq tushunishni osonlashtiradi.
Keyingi o'rinda loyihaning tashqi bog'liqliklarini (dependencies) boshqarish va paketlar bilan ishlash mexanizmini ko'rib chiqamiz.