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:

  • mainmaxsus funksiya, dastur boshlanganda Go o'zi chaqiradi
  • fmt.Print, fmt.Scanichki (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 yaratamiz
  • outputText — 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 parametri
  • float64 (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 — faqat var yoki const.
  • 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, rfv deb 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

  1. outputText funksiyasini yozib, main dagi fmt.Print larni unga almashtiring.
  2. calculateFutureValues ni yozing, inflationRate ni global const qiling.
  3. Mashqdagi kodni o'zingiz boshidan yozing.
  4. calculateFinancials ichida revenue ni main dan to'g'ridan-to'g'ri ishlatishga urinib ko'ring (parametrsiz) — qanday xato chiqadi? Nega? (scope!)

5-dars · → 7-dars — Shartlar: if / else