- Bir neçə və adlı nəticə qaytaran funksiyalar yazmaq
- Variadik funksiyalardan və funksiyaları qiymət kimi ötürməkdən istifadə etmək
- Closure-in xarici dəyişəni necə tutduğunu izah etmək
defer-in icra sırasını və arqumentlərin nə vaxt hesablandığını bilmək
Kalkulyatorda hər dəfə «+» düyməsini basanda eyni toplama qaydası işə düşür. Proqramlaşdırmada belə təkrar istifadə olunan kod parçasına funksiya deyilir. Go funksiyaları bir neçə nəticə qaytara, başqa funksiyaları arqument kimi qəbul edə və öz vəziyyətini «yadda saxlaya» bilir. Bu dərsdə həm də defer ilə tanış olacaqsan — işi funksiyanın sonuna təxirə salan açar sözlə.
Funksiyanın elanı və nəticələri
Funksiya func açar sözü ilə elan olunur: əvvəlcə ad, sonra mötərizədə parametrlər, sonda isə nəticənin tipi. Eyni tipli parametrləri qısaltmaq olar: a int, b int əvəzinə a, b int. Go-nun fərqli cəhəti budur ki, funksiya bir neçə qiymət qaytara bilər: (int, int). Lazım olmayan nəticəni boş identifikator _ ilə atmaq olar.
package main
import "fmt"
func add(a, b int) int {
return a + b
}
func divmod(a, b int) (int, int) {
return a / b, a % b
}
func rectangle(w, h float64) (area, perimeter float64) {
area = w * h
perimeter = 2 * (w + h)
return
}
func main() {
fmt.Println(add(2, 3))
q, r := divmod(17, 5)
fmt.Println(q, r)
_, rest := divmod(10, 4)
fmt.Println(rest)
fmt.Println(rectangle(3, 2.5))
}5 3 2 2 7.5 11
rectangle funksiyasında nəticələrin adı var: (area, perimeter float64). Belə dəyişənlər funksiyanın əvvəlində sıfır qiymətlə yaranır, arqumentsiz return isə onların cari qiymətlərini qaytarır. Son sətirdə gördüyün kimi, çox nəticəli funksiyanın çağırışını birbaşa Println-ə ötürmək də olar.
Variadik funksiyalar və funksiya qiymət kimi
Son parametrin tipindən əvvəl ... yazsan, funksiya istənilən sayda arqument qəbul edər — belə funksiyaya variadik deyilir. fmt.Println da məhz belədir. Funksiyanın içində bu parametr adi dilimdir. Hazır dilimi ötürmək üçün adından sonra ... yazılır: sum(scores...). Go-da funksiyalar həm də adi qiymətdir: onları dəyişənə yazmaq, başqa funksiyaya ötürmək və qaytarmaq olar.
package main
import "fmt"
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func apply(n int, f func(int) int) int {
return f(n)
}
func main() {
fmt.Println(sum())
fmt.Println(sum(1, 2, 3))
scores := []int{90, 85, 70}
fmt.Println(sum(scores...))
square := func(x int) int { return x * x }
fmt.Println(apply(7, square))
}0 6 245 49
Closure-lər
Adsız funksiya birbaşa kodun içində yaradılır: func(x int) int { ... }. Əgər o, xaricindəki dəyişəndən istifadə edirsə, həmin dəyişəni «tutur» və yaşadır — belə funksiyaya closure (qapanma) deyilir. Aşağıdakı counter hər çağırışda yeni sayğac yaradır: hər closure öz count dəyişənini saxlayır.
package main
import "fmt"
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
next := counter()
fmt.Println(next(), next(), next())
other := counter()
fmt.Println(other(), next())
}1 2 3 1 4
next və other iki müstəqil sayğacdır: other() yenidən 1-dən başlayır, next() isə öz hesabını davam etdirib 4 qaytarır. count dəyişəni counter funksiyası bitəndən sonra da yaşayır, çünki onu closure tutub.
var funcs []func()
for i := 0; i < 3; i++ {
i := i // needed before Go 1.22
funcs = append(funcs, func() { fmt.Print(i, " ") })
}var funcs []func()
for i := 0; i < 3; i++ {
funcs = append(funcs, func() { fmt.Print(i, " ") })
}defer: işi sona saxlamaq
defer açar sözü funksiya çağırışını cari funksiya bitənə qədər təxirə salır. Funksiya adi qaydada bitsə də, xəta ilə çıxsa da, təxirə salınmış çağırışlar mütləq icra olunur. Bir neçə defer varsa, onlar tərs sırada — sonuncudan birinciyə doğru işləyir (LIFO, üst-üstə qoyulmuş boşqablar kimi). Diqqət: arqumentlər sonra yox, defer yazılan anda hesablanır.
package main
import "fmt"
func main() {
fmt.Println("start")
for i := 1; i <= 3; i++ {
defer fmt.Println("deferred", i)
}
x := 10
defer fmt.Println("x was", x)
x = 20
fmt.Println("end, x =", x)
}start end, x = 20 x was 10 deferred 3 deferred 2 deferred 1
Nəticəyə bax: x sonradan 20 olsa da, təxirə salınmış çağırış 10 çap etdi, çünki arqument defer sətrində hesablanmışdı. Təxirə salınmış çağırışların hamısı end sətrindən sonra, tərs sırada işlədi.
Əsas fikirlər
- Funksiya
func ad(parametrlər) nəticəşəklində yazılır; eyni tipli parametrlər birləşdirilə bilər:a, b int. - Go funksiyası bir neçə qiymət qaytara bilər; lazımsız nəticə
_ilə atılır. ...Tparametri istənilən sayda arqument qəbul edir; hazır dilims...kimi ötürülür.- Closure xarici dəyişəni tutub saxlayır; Go 1.22-dən hər dövr addımı öz dəyişənini alır.
deferçağırışı funksiyanın sonuna saxlayır, tərs sırada icra edir və arqumentləri dərhal hesablayır.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
func divmod(a, b int) (int, int) funksiyasının düzgün çağırışı hansıdır?