Section 6
6-dars — Funksiyalar
func, parametrlar, return, bir nechta qaytarish qiymati, named return va o'zgaruvchilar qamrovi (scope)
main funksiyamiz kattalashib boryapti. Funksiya — kodning bir bo'lagini nomlab, qayta-qayta ishlatish usuli. Bu darsda o'z funksiyalarimizni yozamiz.
Funksiya nima?
Funksiya — bu "talab bo'yicha kod bloki" (code on demand). Kodni yozasiz, lekin u faqat funksiya chaqirilganda (call) bajariladi. Bizda allaqachon funksiyalar bor:
main— maxsus funksiya, dastur boshlanganda Go o'zi chaqiradifmt.Print,fmt.Scan— ichki (built-in) funksiyalar, Go bilan keladi- Endi esa o'zimiz funksiya yozamiz
Funksiyalarning asosiy foydasi: bir xil kodni takrorlamaymiz (DRY — Don't Repeat Yourself).
1. Oddiy funksiya (parametr bilan)
func outputText(text string) {
fmt.Print(text)
}func— funksiya yaratamizoutputText— nomi (vazifani tasvirlasin)(text string)— parametr: funksiyaga beriladigan kirish.text— nomi,string— tipi (har bir parametrning tipi shart){ }ichi — funksiya tanasi (chaqirilganda bajariladigan kod)
main ichida shunday chaqiramiz:
outputText("Investment Amount: ")"Investment Amount: " qiymati text parametriga boradi. Agar argument bermasangiz, Go xato beradi: not enough arguments.
Bir nechta parametr bir xil tipli bo'lsa, tipni faqat oxirida yozish kifoya:
(a, b int). Har xil tipli bo'lsa:(a int, b string).
2. Qiymat qaytaradigan funksiya (return)
Funksiya natija qaytaradi ham. Qaytarish tipini qavsdan keyin yozamiz:
func getUserInput(infoText string) float64 {
var userInput float64
fmt.Print(infoText)
fmt.Scan(&userInput)
return userInput
}(infoText string)— kirish parametrifloat64(qavsdan keyin) — qaytariladigan tip (Go statik tipli, shuning uchun oldindan e'lon qilinadi)return userInput— qiymatni qaytaradi
Chaqirilganda natijani o'zgaruvchiga olamiz:
revenue := getUserInput("Revenue: ")3. Bir nechta qiymat qaytarish
Go'ning kuchli tomoni — funksiya bir vaqtda bir nechta qiymat qaytara oladi (ko'p tillarda bu yo'q). Tiplarni qavs ichida sanaymiz:
const inflationRate = 2.5
func calculateFutureValues(investmentAmount, expectedReturnRate, years float64) (float64, float64) {
fv := investmentAmount * math.Pow(1+expectedReturnRate/100, years)
rfv := fv / math.Pow(1+inflationRate/100, years)
return fv, rfv
}(float64, float64) — funksiya ikkita float64 qaytaradi. Chaqirganda ikkala natijani olamiz:
futureValue, futureRealValue := calculateFutureValues(investmentAmount, expectedReturnRate, years)4. O'zgaruvchilar qamrovi (scope)
Diqqat: yuqorida inflationRate ni main dan tashqariga chiqardik. Nega?
Go'da funksiya ichida e'lon qilingan o'zgaruvchi/konstanta faqat o'sha funksiyada mavjud — bu uning qamrovi (scope). calculateFutureValues ichidan main dagi o'zgaruvchilarni ko'ra olmaydi.
Yechim ikki xil:
- Global qilish — funksiyalardan tashqarida e'lon qilsangiz, o'zgaruvchi/konstanta butun faylga tegishli bo'ladi (hamma funksiya ko'radi). Lekin tashqarida
:=ishlamaydi — faqatvaryokiconst. - Parametr sifatida uzatish — funksiyaga kerakli qiymatni argument qilib berish.
Biz inflationRate ni global const qildik (u o'zgarmaydi). Lekin investmentAmount, years ni global qilmaymiz — ularni main ichida qoldirib, funksiyaga parametr sifatida uzatamiz.
Nega? Chunki ular foydalanuvchidan keladi. Global qilsak, ular dastlab
0(null qiymat) bo'ladi va tasodifan noto'g'ri joyda ishlatilib qolishi mumkin. Parametr sifatida uzatish — xavfsizroq va tushunarliroq.
5. Nomlangan qaytarish qiymatlari (named return)
Qaytarish qiymatlariga nom ham berish mumkin. Unda ular allaqachon e'lon qilingan bo'ladi (:= emas, = ishlatasiz), return ni bo'sh qoldirsangiz ham bo'ladi:
func calculateFutureValues(investmentAmount, expectedReturnRate, years float64) (fv float64, rfv float64) {
fv = investmentAmount * math.Pow(1+expectedReturnRate/100, years)
rfv = fv / math.Pow(1+inflationRate/100, years)
return // fv va rfv o'zi qaytadi
}Bu — shaxsiy uslub masalasi. Ko'pchilik
return fv, rfvdeb aniq yozishni afzal ko'radi (uzun funksiyada tushunarliroq).
Mashq: profit kalkulyatorini funksiyalar bilan qayta yozing
package main
import "fmt"
func main() {
revenue := getUserInput("Revenue: ")
expenses := getUserInput("Expenses: ")
taxRate := getUserInput("Tax Rate: ")
ebt, profit, ratio := calculateFinancials(revenue, expenses, taxRate)
fmt.Printf("%.1f\n", ebt)
fmt.Printf("%.1f\n", profit)
fmt.Printf("%.3f\n", ratio)
}
func calculateFinancials(revenue, expenses, taxRate float64) (float64, float64, float64) {
ebt := revenue - expenses
profit := ebt * (1 - taxRate/100)
ratio := ebt / profit
return ebt, profit, ratio
}
func getUserInput(infoText string) float64 {
var userInput float64
fmt.Print(infoText)
fmt.Scan(&userInput)
return userInput
}Diqqat qiling: main qisqa va o'qishga oson bo'lib qoldi. Har bir funksiya bitta vazifa bajaradi — bu "Separation of Concerns" (vazifalarni ajratish) prinsipi, professional kodning belgisi.
O'zingiz sinab ko'ring
outputTextfunksiyasini yozib,maindagifmt.Printlarni unga almashtiring.calculateFutureValuesni yozing,inflationRateni globalconstqiling.- Mashqdagi kodni o'zingiz boshidan yozing.
calculateFinancialsichidarevenuenimaindan to'g'ridan-to'g'ri ishlatishga urinib ko'ring (parametrsiz) — qanday xato chiqadi? Nega? (scope!)