- Struktur elan etmək, literal ilə yaratmaq və
%+vilə çap etmək &və*ilə göstəricilərdən istifadə etmək- Qiymət və göstərici qəbuledicisi arasında düzgün seçim etmək
NewXkonstruktor funksiyaları və strukturların daxil edilməsi ilə işləmək
Şagird haqqında məlumat — ad, yaş, orta bal — bir yerdə saxlanılmalıdır. Onları üç ayrı dəyişəndə saxlamaq əlverişsizdir. Go-da sinif yoxdur, əvəzində strukturlar (struct) var: onlar əlaqəli sahələri bir tipdə birləşdirir, metodlar isə bu tipə davranış əlavə edir. Bu dərsdə həm də göstəriciləri öyrənəcəksən — onlarsız funksiya orijinal məlumatı dəyişə bilməz.
Strukturlar
Struktur type Ad struct { ... } şəklində elan olunur, içində isə sahələr və onların tipləri sadalanır. Obyekt yaratmaq üçün struktur literalı yazılır: Student{Name: "Aysel", Age: 15}. Sahələrə nöqtə ilə müraciət olunur: s.Name. Qiymət verilməyən sahə sıfır qiymət alır, ona görə boş struktur da tam işlək qiymətdir.
package main
import "fmt"
type Student struct {
Name string
Age int
Score float64
}
func main() {
s := Student{Name: "Aysel", Age: 15, Score: 92.5}
var empty Student
s.Age++
fmt.Println(s)
fmt.Printf("%+v\n", s)
fmt.Printf("%+v\n", empty)
fmt.Println(s.Name, s.Score)
}{Aysel 16 92.5}
{Name:Aysel Age:16 Score:92.5}
{Name: Age:0 Score:0}
Aysel 92.5%v (və Println) yalnız qiymətləri göstərir, %+v isə sahələrin adlarını da əlavə edir — sazlama (debug) zamanı bu çox faydalıdır. Bütün sahələri müqayisə oluna bilən strukturları == ilə müqayisə etmək olar: iki Student bütün sahələri eyni olduqda bərabərdir.
Göstəricilər
Go-da funksiyaya ötürülən hər şey surətlənir. Funksiya parametri dəyişsə, çağıran tərəfin dəyişəni toxunulmaz qalır. Orijinalı dəyişmək üçün göstərici lazımdır — dəyişənin yaddaşdakı ünvanı. &x ünvanı götürür, *p isə həmin ünvandakı qiyməti oxuyur və ya dəyişir. *int tipi «int-ə göstərici» deməkdir. Go-da göstərici hesabı (C-dəki kimi p++) yoxdur, ona görə göstəricilər təhlükəsizdir.
package main
import "fmt"
func doubleValue(n int) {
n *= 2
}
func doublePointer(n *int) {
*n *= 2
}
func main() {
x := 5
p := &x
*p = 7
fmt.Println(x, *p, p == &x)
doubleValue(x)
fmt.Println(x)
doublePointer(&x)
fmt.Println(x)
}7 7 true 7 14
Başqa dəyişənin yaddaşdakı ünvanını saxlayan qiymət. Sıfır qiyməti nil-dir. & ünvanı götürür, * isə həmin ünvandakı qiymətə müraciət edir.
Metodlar: qiymət və göstərici qəbulediciləri
Metod — xüsusi parametri, yəni qəbuledicisi (receiver) olan funksiyadır. Qəbuledici func sözü ilə metodun adı arasında yazılır: func (a Account) Summary() string. Əgər qəbuledici qiymətdirsə (a Account), metod obyektin surəti ilə işləyir. Əgər göstəricidirsə (a *Account), metod orijinal obyekti dəyişə bilir.
package main
import "fmt"
type Account struct {
Owner string
Balance float64
}
func (a Account) Summary() string {
return fmt.Sprintf("%s: %.2f AZN", a.Owner, a.Balance)
}
func (a *Account) Deposit(amount float64) {
a.Balance += amount
}
func (a Account) BrokenDeposit(amount float64) {
a.Balance += amount
}
func main() {
acc := Account{Owner: "Murad", Balance: 100}
acc.Deposit(50)
acc.BrokenDeposit(1000)
fmt.Println(acc.Summary())
p := &acc
p.Deposit(25.5)
fmt.Println(p.Summary())
}Murad: 150.00 AZN Murad: 175.50 AZN
BrokenDeposit 1000 manat əlavə etməyə çalışdı, amma balans dəyişmədi, çünki metod surət üzərində işləyirdi. Diqqət et: acc göstərici deyil, amma acc.Deposit(50) işləyir — Go avtomatik olaraq (&acc).Deposit(50) çağırır. Eyni şəkildə göstərici p üzərindən qiymət qəbuledicili Summary metodunu da çağırmaq olar.
| Qəbuledici | Nə vaxt seçməli |
|---|---|
func (a Account) | Metod obyekti dəyişmir və tip kiçikdir (bir neçə sahə, time.Time kimi). |
func (a *Account) | Metod sahələri dəyişir, tip böyükdür və ya içində sync.Mutex kimi surətlənməməli sahə var. |
type Counter struct {
value int
}
func (c Counter) Increment() {
c.value++ // changes a copy
}type Counter struct {
value int
}
func (c *Counter) Increment() {
c.value++ // changes the original
}Konstruktorlar və daxiletmə
Go-da xüsusi konstruktor yoxdur. Əvəzində adı New ilə başlayan adi funksiya yazılır: NewTeacher(...) yeni obyekt yaradıb ona göstərici qaytarır. Varislik də yoxdur — Go kompozisiyaya üstünlük verir. Bir strukturu başqasının içinə adsız sahə kimi daxil etmək (embedding) olar: onda daxil edilmiş strukturun sahələri və metodları xarici strukturda birbaşa əlçatan olur.
package main
import "fmt"
type Person struct {
Name string
}
func (p Person) Greet() string {
return "Hi, I am " + p.Name
}
type Teacher struct {
Person
Subject string
}
func NewTeacher(name, subject string) *Teacher {
return &Teacher{Person: Person{Name: name}, Subject: subject}
}
func main() {
t := NewTeacher("Leyla", "Math")
fmt.Println(t.Greet())
fmt.Println(t.Name, "teaches", t.Subject)
fmt.Printf("%+v\n", *t)
}Hi, I am Leyla
Leyla teaches Math
{Person:{Name:Leyla} Subject:Math}Əsas fikirlər
- Struktur əlaqəli sahələri bir tipdə birləşdirir;
%+vonu sahə adları ilə çap edir. - Go hər şeyi qiymətlə ötürür; orijinalı dəyişmək üçün göstərici (
&x,*p) lazımdır. - Qiymət qəbuledicisi surətlə, göstərici qəbuledicisi orijinalla işləyir; Go
&-i özü əlavə edir. nilgöstərici üzərindən sahəyə müraciət panic yaradır.- Konstruktor əvəzinə
NewXfunksiyaları, varislik əvəzinə strukturların daxil edilməsi (kompozisiya) işlədilir.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
fmt.Printf("%+v", Point{X: 1, Y: 2}) nə çıxarır?