Skip to Content
Generics🧩 Mashqlar

Mashqlar

Bu bo’limda generics’ni amalda mustahkamlaysiz: type parameter, type inference, constraint (comparable, cmp.Ordered, union, ~) va generic turlar. Har mashqni avval o’zingiz yozib ishga tushiring, keyin yechimni oching. Kod Go 1.21+ (cmp paketi) uchun.

1. Generic First

Slice’ning birinchi elementini qaytaradigan generic First[T any] funksiyasini yozing. Bo’sh slice bo’lsa T ning nol qiymatini va false qaytarsin. Kutilgan chiqish quyidagicha.

Yechimni ko’rish

first.go
package main import "fmt" func First[T any](s []T) (T, bool) { var zero T // T ning nol qiymati — qaysi tur bo'lsa ham ishlaydi if len(s) == 0 { return zero, false } return s[0], true } func main() { fmt.Println(First([]int{10, 20, 30})) // type inference: T=int fmt.Println(First([]string{})) // bo'sh slice }
$ go run first.go 10 true false

Bo’sh string slice uchun nol qiymat "" (bo’sh satr), shuning uchun ikkinchi qatorda false dan oldin bo’shliq ko’rinadi. First([]int{...}) deb yozmadik — Go turni argumentdan o’zi aniqladi.

2. Map — bir turdan boshqasiga

[]T ni []U ga aylantiradigan Map[T, U any](s []T, f func(T) U) []U yozing. Uni int slice’ni har elementi ikki barobar string ga aylantirishda ishlating. Kirish []int{1,2,3} uchun kutilgan chiqish: [2x 4x 6x].

Yechimni ko’rish

map.go
package main import ( "fmt" "strconv" ) // Ikkita type parameter: kirish T va chiqish U. func Map[T, U any](s []T, f func(T) U) []U { result := make([]U, len(s)) for i, v := range s { result[i] = f(v) } return result } func main() { nums := []int{1, 2, 3} out := Map(nums, func(n int) string { return strconv.Itoa(n*2) + "x" }) fmt.Println(out) }
$ go run map.go [2x 4x 6x]

T=int, U=string — ikkovini ham type inference argumentlardan aniqladi, Map[int, string] deb yozish shart emas.

3. Sum — union constraint bilan

int ham, float64 ham qabul qiladigan Sum yozing. Buning uchun ~int | ~float64 union constraint kerak. type Ball float64 kabi maxsus tur ham ~ tufayli mos kelsin. Kutilgan chiqish quyidagicha.

Yechimni ko’rish

sum.go
package main import "fmt" // ~int | ~float64 — asosiy turi shu bo'lgan barcha turlar. type Number interface { ~int | ~float64 } type Ball float64 // asosiy turi float64 func Sum[T Number](nums []T) T { var total T // nol qiymat: int uchun 0, float64 uchun 0.0 for _, n := range nums { total += n } return total } func main() { fmt.Println(Sum([]int{1, 2, 3, 4})) fmt.Println(Sum([]float64{1.5, 2.5})) fmt.Println(Sum([]Ball{3.5, 4.5})) // ~float64 bo'lgani uchun mos }
$ go run sum.go 10 4 8

~ bo’lmaganida Sum([]Ball{...}) kompilyatsiya bo’lmasdi — Ball alohida tur, lekin asosiy turi float64.

4. Index — comparable bilan

Slice ichidan berilgan elementning indeksini qaytaradigan Index[T comparable] yozing (topilmasa -1). == ishlatgani uchun constraint comparable bo’lishi shart. Kutilgan chiqish quyidagicha.

Yechimni ko’rish

index.go
package main import "fmt" // comparable — == va != bilan solishtirsa bo'ladigan turlar. func Index[T comparable](s []T, target T) int { for i, v := range s { if v == target { // comparable shuni mumkin qiladi return i } } return -1 } func main() { fmt.Println(Index([]string{"a", "b", "c"}, "b")) // 1 fmt.Println(Index([]int{5, 6, 7}, 9)) // topilmadi }
$ go run index.go 1 -1

comparable o’rniga any yozsak, v == target kompilyatsiya bo’lmasdi — har qanday tur == ni qo’llab-quvvatlamaydi (masalan slice’larni solishtirib bo’lmaydi).

5. Generic Stack[T]

Istalgan tur bilan ishlaydigan Stack[T any] yasang: Push va Pop metodlari bo’lsin. Pop bo’sh stack’da nol qiymat va false qaytarsin. Kutilgan chiqish quyidagicha.

Yechimni ko’rish

stack.go
package main import "fmt" type Stack[T any] struct { items []T } // Receiver'da T ni qayta yozamiz: (s *Stack[T]). func (s *Stack[T]) Push(item T) { s.items = append(s.items, item) } func (s *Stack[T]) Pop() (T, bool) { var zero T if len(s.items) == 0 { return zero, false } last := s.items[len(s.items)-1] s.items = s.items[:len(s.items)-1] return last, true } func main() { st := &Stack[int]{} // instantiation: Stack[int] st.Push(1) st.Push(2) fmt.Println(st.Pop()) // 2 true fmt.Println(st.Pop()) // 1 true fmt.Println(st.Pop()) // bo'sh: 0 false }
$ go run stack.go 2 true 1 true 0 false

Stack[int] va Stack[string] alohida turlar; st ga string push qilib bo’lmaydi — kompilyator to’xtatadi.

6. MaxBy — cmp.Ordered kaliti bilan

Struct slice’dan berilgan kalit bo’yicha eng kattasini topadigan MaxBy yozing. Element turi T any, kalit turi esa cmp.Ordered bo’lsin (K ni argument funksiya qaytaradi). Talabalar ichidan eng yuqori bahoni toping. Kutilgan chiqish: Vali 90.

Yechimni ko’rish

maxby.go
package main import ( "cmp" "fmt" ) // T — element turi (any), K — kalit turi (tartiblanadigan). func MaxBy[T any, K cmp.Ordered](s []T, key func(T) K) T { best := s[0] for _, v := range s[1:] { if key(v) > key(best) { // K cmp.Ordered bo'lgani uchun > joiz best = v } } return best } type Student struct { Name string Grade int } func main() { students := []Student{ {"Ali", 75}, {"Vali", 90}, {"Guli", 82}, } top := MaxBy(students, func(s Student) int { return s.Grade }) fmt.Println(top.Name, top.Grade) }
$ go run maxby.go Vali 90

Ikki type parameter (T va K) va bitta constraint (K cmp.Ordered) birga ishladi. Student ni to’g’ridan-to’g’ri solishtirib bo’lmaydi, lekin uning Grade kaliti tartiblanadi — shuning uchun key funksiyasini uzatdik.

Last updated on