Rumah > pembangunan bahagian belakang > Golang > Pergi kepingan dan subslic: Memahami memori bersama dan mengelakkan `tambah ()` perangkap

Pergi kepingan dan subslic: Memahami memori bersama dan mengelakkan `tambah ()` perangkap

Barbara Streisand
Lepaskan: 2025-01-29 00:21:10
asal
846 orang telah melayarinya

Go Slices and Subslices: Understanding Shared Memory and Avoiding `append()` Pitfalls

dalam pemahaman mengenai pengiraan bahasa Go: memori bersama dan

perangkap append() Hai semua! Selamat datang ke blog saya. Sekiranya anda berada di sini, anda mungkin hanya bersentuhan dengan Golang, atau anda adalah pemaju yang berpengalaman, dan anda ingin memahami prinsip kerja dalaman bahagian ini. Oleh itu mari kita mulakan!

bahasa Go sangat dipuji kerana kesederhanaan dan kecekapannya -seperti orang sering berkata, "Bahasa Go adalah untuk menyelesaikan kerja." Bagi pemaju dari C, C atau Java dan bahasa lain, tatabahasa mudah dan kemudahan penggunaan bahasa Go menyegarkan. Walau bagaimanapun, walaupun dalam bahasa Go, beberapa ciri mungkin mengelirukan pemaju, terutamanya apabila memproses kepingan dan sub -klip. Mari kita memperkenalkan kehalusan ini dan lebih memahami bagaimana untuk mengelakkan perangkap biasa

dan dihiris untuk berkongsi ingatan.

append() Apakah kepingan dalam bahasa Go?

Biasanya, apabila anda memerlukan struktur data untuk menyimpan satu siri nilai, mengiris adalah pilihan pertama dalam bahasa Go. Fleksibiliti mereka berasal dari fakta seperti itu: panjangnya bukan sebahagian daripada jenisnya. Ciri ini mengatasi sekatan array, membolehkan kita membuat satu fungsi yang dapat mengendalikan mana -mana kepingan dan membolehkan kepingan itu meningkat atau berkembang mengikut keperluan. Walaupun kepingan mempunyai beberapa persamaan dengan array, seperti pengindeksan dan panjang, mereka mempunyai kaedah pengurusan data yang berbeza. Slice bertindak sebagai rujukan kepada array asas, yang sebenarnya menyimpan data kepingan. Pada dasarnya, kepingan memberikan pandangan beberapa atau semua elemen array. Oleh itu, apabila anda membuat kepingan, GO akan secara automatik memproses pelbagai bawah untuk mewujudkan elemen/data yang dihiris.

Memori bersama dihiris

Arahan adalah blok memori yang berterusan, tetapi apa yang membuatkan kepingan menarik adalah bagaimana mereka memetik ingatan ini. Mari memecahkan struktur kepingan:

Apabila anda membuat kepingan, ia mengandungi tiga komponen:

Puisi menunjuk kepada array yang mendasari
<code class="language-go">type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int           // 切片中的元素数量
    cap   int           // 底层数组的容量
}</code>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Panjang penghirisan (bilangan elemen yang terkandung)

    kapasiti (bilangan elemen yang boleh mengandungi sebelum keperluan meningkat)
  1. Ini adalah tempat yang menjadi menarik. Sekiranya anda mempunyai pelbagai keping yang diperolehi dari array yang sama, perubahan yang dibuat oleh kepingan akan ditunjukkan dalam kepingan lain kerana mereka berkongsi array yang sama. len
  2. mari kita lihat contoh berikut:
  3. cap
  4. Memahami kapasiti penghirisan

Sebelum kita semakin mendalam, mari kita cuba memahami kapasiti penghirisan

. Apabila anda mendapat sub -plices dari penghirisan bahasa Go yang sedia ada, kapasiti

<code class="language-go">package main

import "fmt"

func main() {
    // 创建一个具有初始值的切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片——两个切片共享相同的底层数组!
    subslice := original[1:3]

    fmt.Println("未修改的子切片:", subslice)  // 输出 => 未修改的子切片: [2 3]

    // 修改子切片
    subslice[0] = 42

    fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5]
    fmt.Println("修改后的子切片:", subslice)  // 输出 => 修改后的子切片: [42 3]
}</code>
Salin selepas log masuk
Salin selepas log masuk
sub -slicing baru ditentukan oleh kapasiti selebihnya dari kepingan asal dari sub -bahagian. Mari kita hancurkan sedikit:

Apabila anda membuat kepingan dari tatasusunan, panjang kepingan adalah bilangan elemen yang asalnya terkandung, dan kapasitinya adalah jumlah unsur yang dapat dikandung sebelum ia perlu berkembang.

Dapatkan sub -slicing

apabila anda mendapat sub -slicing dari kepingan yang ada:

  • panjang adalah bilangan elemen yang anda tentukan.
  • Kapasiti
  • Mengira kapasiti kepingan asal tolak indeks permulaan sub -klip.
  • mari kita lihat contoh terperinci:

<code class="language-go">type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int           // 切片中的元素数量
    cap   int           // 底层数组的容量
}</code>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Slice asal mempunyai 5 elemen, dan panjang dan kapasiti adalah 5.
  • Apabila anda menggunakan , ia menunjuk kepada unsur -unsur dari indeks 1 hingga 3 (2, 3, 4).
  • panjang subslice := original[1:4]
  • adalah 4-1 = 3.
  • subslice Kapasiti adalah 5-1 = 4, kerana ia bermula dari indeks 1 dan termasuk unsur-unsur hingga akhir kepingan asal.
  • subslice perangkap!
  • Ini adalah di mana pemaju sering terperangkap. Fungsi dalam bahasa Go boleh menyebabkan tingkah laku yang tidak dijangka apabila memproses sub -bahagian.

Perkongsian kapasiti yang tidak digunakan append() kapasiti

sub -slicing termasuk unsur -unsur yang tidak tergolong dalam panjangnya tetapi terletak di julat kapasiti pengirim asal. Ini bermakna bahawa jika sub -plices meningkat, ia boleh mengakses atau mengubah suai unsur -unsur ini.

append() mari kita pertimbangkan contoh ini:

Pada mulanya menunjuk kepada 2, 3, kapasiti adalah 4 (ia boleh tumbuh hingga akhir kepingan asal). Apabila anda menambah 60, 70 ke , ia menggunakan kapasiti lebihan kepingan asal.

dan

kedua -duanya mencerminkan perubahan ini kerana mereka berkongsi array yang sama.
<code class="language-go">package main

import "fmt"

func main() {
    // 创建一个具有初始值的切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片——两个切片共享相同的底层数组!
    subslice := original[1:3]

    fmt.Println("未修改的子切片:", subslice)  // 输出 => 未修改的子切片: [2 3]

    // 修改子切片
    subslice[0] = 42

    fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5]
    fmt.Println("修改后的子切片:", subslice)  // 输出 => 修改后的子切片: [42 3]
}</code>
Salin selepas log masuk
Salin selepas log masuk
  • Adakah anda terkejut? subslice Operasi diubahsuai kepingan asal kerana terdapat kapasiti yang cukup dalam array yang mendasari. Walau bagaimanapun, jika kita melebihi skop kapasiti atau unsur -unsur tambahan melebihi permit kapasiti, GO akan memperuntukkan array baru untuk sub -bahagian untuk memecahkan perkongsian dengan mengiris asal:
  • subslice Dalam kes ini,
  • mencipta array asas baru kerana kapasiti asal telah melebihi.
  • original Amalan terbaik untuk mengelakkan perangkap subslice

menjelaskan kapasiti append()

<code class="language-go">func main() {
    // 原始切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片
    subslice := original[1:4] // 指向元素 2, 3, 4

    fmt.Println("子切片:", subslice)    // 输出 => 子切片: [2 3 4]
    fmt.Println("子切片的长度:", len(subslice)) // 输出 => 子切片的长度: 3
    fmt.Println("子切片的容量:", cap(subslice)) // 输出 => 子切片的容量: 4
}</code>
Salin selepas log masuk

append() kelebihan utama ialah:

i. Ini penting -bukan sekadar kepala seksyen baru, tetapi array baru dalam ingatan. ii. Ini seperti salinan fail dan bukannya berkongsi fail asal.

  • Gunakan ekspresi slice lengkap
<code class="language-go">func main() {
    original := []int{1, 2, 3, 4, 5}
    subslice := original[1:3] // 指向元素 2, 3

    fmt.Println("追加前原始切片:", original) // 输出 => [1 2 3 4 5]
    fmt.Println("追加前子切片:", subslice)       // 输出 => [2 3]
    fmt.Println("子切片的容量:", cap(subslice))    // 输出 => 4

    // 在容量范围内追加到子切片
    subslice = append(subslice, 60, 70)

    // 追加到子切片后打印
    fmt.Println("追加后原始切片:", original)  // 输出 => [1 2 3 60 70]
    fmt.Println("追加后子切片:", subslice)        // 输出 => [2 3 60 70]
}</code>
Salin selepas log masuk

Apabila lulus kepingan ke fungsi yang tidak boleh mengubah suai data asal, pertimbangkan bukan kebolehpasaran

make([]int, len(subslice))

kelebihan utama ialah: copy()

i.
    ii.

    III.

    ingat:

    Slice adalah rujukan kepada array yang mendasari
    • Sub -Slicing dan Memori Perkongsian Ibu Bapa
    • sama ada penciptaan array asas baru bergantung kepada kapasiti
    • Apabila menambahkan unsur -unsur elemen sub -slicing dengan kapasiti, ia akan mengubah suai data penghirisan induk. append()
    • Apabila anda ingin mengelakkan perkongsian, sila gunakan Pengurusan Memori Eksplisit
    • Semasa memproses sub -plices, sila lakukan mana -mana operasi berikut:
    • Saya doakan kod gembira. Ingat, semakin besar keupayaan, semakin besar tanggungjawab, terutama dalam perkongsian ingatan! ?
<code class="language-go">type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int           // 切片中的元素数量
    cap   int           // 底层数组的容量
}</code>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Tahniah untuk membaca artikel ini.

Adakah anda fikir sumber ini membantu? Adakah anda mempunyai soalan? Atau adakah anda menemui ralat atau kesilapan? Sila tinggalkan maklum balas anda dalam komen.

Jangan lupa untuk berkongsi sumber ini dengan orang lain yang mungkin mendapat manfaat daripadanya. Ikuti saya untuk mendapatkan lebih banyak maklumat.

Atas ialah kandungan terperinci Pergi kepingan dan subslic: Memahami memori bersama dan mengelakkan `tambah ()` perangkap. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan