Go’da interface
Interface turdan qanday ma’lumot saqlashini emas, qanday metodlarga ega bo‘lishini talab qiladi. Shu metodlar to‘plamiga mos keladigan har qanday tur interface’ni avtomatik bajaradi. Alohida implements kalit so‘zi yo‘q.
Bu yondashuv funksiyani aniq structga emas, kerakli xatti-harakatga bog‘laydi. Masalan, xabar yuboruvchi funksiya email yoki SMS turining ichki tuzilishini bilishi shart emas; unga Send metodi kifoya.
Interface e’lon qilish va bajarish
package main
import "fmt"
type Sender interface {
Send(message string) error
}
type EmailSender struct {
Address string
}
func (e EmailSender) Send(message string) error {
if e.Address == "" {
return fmt.Errorf("email manzili bo‘sh")
}
fmt.Printf("%s manziliga: %s\n", e.Address, message)
return nil
}
func Notify(sender Sender, message string) error {
return sender.Send(message)
}
func main() {
email := EmailSender{Address: "[email protected]"}
if err := Notify(email, "Buyurtma tayyor"); err != nil {
fmt.Println("Xato:", err)
}
}
Natija:
[email protected] manziliga: Buyurtma tayyor
EmailSenderda aynan Send(string) error metodi borligi uchun u Senderga mos keladi. Quyidagi kompilyatsiya vaqtidagi tekshiruv real loyihalarda foydali:
Metod nomi bir xil bo‘lishi yetmaydi; parametr va qaytish turlari ham aynan mos bo‘lishi kerak.
Kichik interface’lar
Interface’ni odatda undan foydalanuvchi paket e’lon qiladi va faqat kerakli metodlarni talab qiladi. Bitta yoki bir nechta metodli kichik interface’lar implementatsiya qilish, testda almashtirish va qayta ishlatish uchun qulay. Standart kutubxonadagi io.Reader faqat Read metodini talab qilishi bunga yaxshi misol.
Interface’ga boshqa interface’ni joylashtirib metodlar to‘plamini birlashtirish mumkin:
type Reader interface {
Read([]byte) (int, error)
}
type Writer interface {
Write([]byte) (int, error)
}
type ReadWriter interface {
Reader
Writer
}
Dynamic type va dynamic value
Interface qiymati amalda ikki qism bilan tushuntiriladi:
- dynamic type — interface ichiga joylangan aniq tur;
- dynamic value — o‘sha turdagi aniq qiymat.
package main
import "fmt"
func main() {
var value any = 42
fmt.Printf("Tur: %T, qiymat: %v\n", value, value)
value = "Go"
fmt.Printf("Tur: %T, qiymat: %v\n", value, value)
}
Natija:
any — interface{}ning aliasi. U istalgan qiymatni qabul qiladi, ammo aniq xatti-harakatni ifodalamaydi. Imkon bo‘lsa, kerakli metodli interface yoki generics orqali type safety’ni saqlang.
nil interface tuzog‘i
Interface faqat dynamic type ham, dynamic value ham yo‘q bo‘lsa nilga teng:
package main
import "fmt"
type MyError struct{}
func (e *MyError) Error() string { return "xato" }
func main() {
var pointer *MyError
var err error = pointer
fmt.Println(pointer == nil)
fmt.Println(err == nil)
fmt.Printf("%T %v\n", err, err)
}
Natija:
err ichida dynamic type *MyError bor, shuning uchun dynamic value nil bo‘lsa ham interface nil emas. Xato qaytaruvchi funksiya muvaffaqiyat holatida typed nil pointer emas, to‘g‘ridan-to‘g‘ri nil qaytarishi kerak.
Type assertion va type switch
Interface ichidagi aniq qiymat kerak bo‘lsa, xavfsiz type assertion ishlatiladi:
package main
import "fmt"
func describe(value any) {
switch v := value.(type) {
case int:
fmt.Println("Butun son:", v)
case string:
fmt.Println("Satr:", v)
default:
fmt.Printf("Boshqa tur: %T\n", v)
}
}
func main() {
describe(42)
describe("Go")
}
Natija:
Bitta tur uchun v, ok := value.(string) shakli ishlatiladi. oksiz noto‘g‘ri assertion panic beradi.
Pointer receiver ta’siri
Agar talab qilinadigan metod *T receiver bilan e’lon qilingan bo‘lsa, interface’ni *T bajaradi, T emas. Bu method set qoidasidir. Interface’ga qiymat berishda kompilyator oddiy metod chaqiruvidagidek avtomatik manzil olmaydi.
Xulosa
- Interface metodlar to‘plamini ifodalaydi va yashirin bajariladi.
- Kichik, iste’molchi ehtiyojiga mos interface’lar afzal.
- Interface qiymatida dynamic type va dynamic value bor.
- Typed nil pointer saqlagan interface
nilemas. - Type assertion’da
comma okshaklipanicning oldini oladi.
Keyingi darsda Go’da alohida enum kalit so‘zi bo‘lmasa ham, nomlangan tur va iota bilan cheklangan konstantalar yaratish o‘rganiladi.