Go / Slice үйлдлүүд

Slice үйлдлүүд

Өмнөх хичээлд slice үүсгэж, append ашиглаж сурсан. Энэ хичээлд slice-тай ажиллах илүү дэвшилтэт үйлдлүүдийг судална — элемент устгах, slice хуулах, болон capacity гэх ойлголтыг тайлбарлана.

Эдгээр үйлдлүүдийг мэдсэнээр бодит программ бичихэд тохиолдох ихэнх нөхцлийг шийдэж чадна.

Slice хуулах — copy

copy функц нь нэг slice-н утгуудыг нөгөөд хуулна. Энэ нь чухал — учир нь slice хуулахгүй бол хоёр хувьсагч нэг санах ойг заах тул нэгийг нь өөрчлөхөд нөгөө нь ч өөрчлөгдөнө.

go
package main

import "fmt"

func main() {
    эх := []int{1, 2, 3, 4, 5}

    // Шинэ slice үүсгэж хуулна
    хуулбар := make([]int, len(эх))
    copy(хуулбар, эх)

    // Хуулбарыг өөрчилсөн ч эх өөрчлөгдөхгүй
    хуулбар[0] = 99

    fmt.Println("Эх:", эх)           // [1 2 3 4 5]
    fmt.Println("Хуулбар:", хуулбар) // [99 2 3 4 5]
}

Дэлгэцэнд:

код
Эх: [1 2 3 4 5]
Хуулбар: [99 2 3 4 5]

copy(хуулбар, эх) нь "эх slice-н утгуудыг хуулбар slice-д хуул" гэсэн үг. Хуулсны дараа тэд бие даасан slice болно.

Элемент устгах

Go-д slice-с элемент устгах суурилагдсан функц байхгүй. Харин append болон хэсэглэлтийг хослуулан ашиглана:

go
package main

import "fmt"

func main() {
    өнгөнүүд := []string{"улаан", "ногоон", "цэнхэр", "шар", "цагаан"}

    // 2 дугаар index (цэнхэр) устгах
    устгах := 2
    өнгөнүүд = append(өнгөнүүд[:устгах], өнгөнүүд[устгах+1:]...)

    fmt.Println(өнгөнүүд)          // [улаан ногоон шар цагаан]
    fmt.Println("Урт:", len(өнгөнүүд)) // 4
}

Дэлгэцэнд:

код
[улаан ногоон шар цагаан]
Урт: 4

өнгөнүүд[:2] нь "цэнхэр"-ийн өмнөх хэсэг, өнгөнүүд[3:] нь "цэнхэр"-ийн дараах хэсэг. append тэдгээрийг нэгтгэнэ. Ингэснээр "цэнхэр" алга болно.

len ба cap — урт ба хүчин чадал

Slice-д хоёр чухал шинж чанар байдаг: len (одоогийн элементийн тоо) ба cap (нийт хүчин чадал):

go
package main

import "fmt"

func main() {
    // make([]int, урт, хүчин_чадал)
    с := make([]int, 3, 10)

    fmt.Println("Урт:", len(с))          // 3
    fmt.Println("Хүчин чадал:", cap(с))  // 10

    с = append(с, 42)
    fmt.Println("append дараа урт:", len(с))         // 4
    fmt.Println("append дараа хүчин чадал:", cap(с)) // 10 — өөрчлөгдөөгүй
}

Дэлгэцэнд:

код
Урт: 3
Хүчин чадал: 10
append дараа урт: 4
append дараа хүчин чадал: 10

cap нь slice-д хэдэн элемент багтах боломжтой болохыг заана. Хэрэв append хийхэд хүчин чадал хүрэлцэхгүй бол Go нь автоматаар хоёр дахин том санах ой гарган шилжүүлнэ. Урьдчилан cap тогтоох нь үүнийг сэргийлж гүйцэтгэлийг сайжруулдаг.

Slice-г функцт дамжуулах

Slice-г функцт дамжуулахад pointer шиг ажилладаг — функц дотор өөрчилсөн утга эх slice-д нөлөөлнө:

go
package main

import "fmt"

func хоёрдахин(тоонууд []int) {
    for i := range тоонууд {
        тоонууд[i] *= 2
    }
}

func main() {
    утгууд := []int{1, 2, 3, 4, 5}
    fmt.Println("Өмнө:", утгууд)

    хоёрдахин(утгууд)
    fmt.Println("Дараа:", утгууд)
}

Дэлгэцэнд:

код
Өмнө: [1 2 3 4 5]
Дараа: [2 4 6 8 10]

Slice нь дотроо массивын pointer агуулдаг тул функцт дамжуулахад хуулбар үүсэхгүй, шууд ажилладаг. Энэ нь гүйцэтгэлийн хувьд сайн шинж юм.

Дараагийн хичээлд:

Map буюу түлхүүр-утга хосын өгөгдлийн бүтцийг судална. Map нь "Нэр → Утас дугаар" гэх мэт хос мэдээллийг хадгалахад хамгийн тохиромжтой бүтэц юм.