03.切片操作

在 Go 语言中,切片(slice)提供了许多强大的操作,可以帮助开发者灵活地处理数据。下面是一些常见的切片操作及其示例:

1. 创建和初始化切片

使用字面量初始化

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    fmt.Println("Slice:", slice)
}

 

使用 make 函数初始化

package main

import "fmt"

func main() {
    slice := make([]int, 5)
    fmt.Println("Slice with make:", slice)
}

 

从数组或其他切片创建

package main

import "fmt"
 
func main() {
    arr := [5]int{10, 20, 30, 40, 50}
    slice := arr[1:4]
    fmt.Println("Slice from array:", slice)
}

 

2. 访问和修改切片元素

访问元素

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    fmt.Println("Element at index 0:", slice[0])
}

 

修改元素

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    slice[1] = 20
    fmt.Println("Modified slice:", slice)
}

 

3. 获取切片的长度和容量

获取长度

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    fmt.Println("Length:", len(slice))
}

 

获取容量

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    fmt.Println("Capacity:", cap(slice))
}

 

4. 动态增加切片元素

使用 append 函数

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3}
    slice = append(slice, 4, 5)
    fmt.Println("Appended slice:", slice)
}

 

5. 切片的切片操作

从切片中创建子切片

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    subSlice := slice[1:4]
    fmt.Println("Sub-slice:", subSlice)
}

 

6. 遍历切片

使用 for 循环

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    for i := 0; i < len(slice); i++ {
        fmt.Println(slice[i])
    }
}

 

使用 range 关键字

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    for index, value := range slice {
        fmt.Printf("Index: %d, Value: %d\n", index, value)
    }
}

 

7. 切片的拷贝

使用 copy 函数

package main

import "fmt"

func main() {
    source := []int{1, 2, 3}
    destination := make([]int, len(source))
    copy(destination, source)
    fmt.Println("Destination slice:", destination)
}

 

8. 删除切片中的元素

删除切片中的元素通常需要使用切片的切片操作。

删除第 i 个元素

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    i := 2
    slice = append(slice[:i], slice[i+1:]...)
    fmt.Println("After deletion:", slice)
}

 

删除开头的元素

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    slice = slice[1:]
    fmt.Println("After deleting first element:", slice)
}

 

删除末尾的元素

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    slice = slice[:len(slice)-1]
    fmt.Println("After deleting last element:", slice)
}

 

9. 多维切片

定义和初始化多维切片

package main

import "fmt"

func main() {
    matrix := [][]int{
        {1, 2, 3},
        {4, 5, 6},
    }
    fmt.Println("2D Slice:", matrix)
}

 

遍历多维切片

package main

import "fmt"

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

    for i := 0; i < len(matrix); i++ {
        for j := 0; j < len(matrix[i]); j++ {
            fmt.Printf("matrix[%d][%d] = %d\n", i, j, matrix[i][j])
        }
    }
}

 

切片操作的总结

  切片是 Go 语言中处理动态数组的核心工具,提供了比数组更为灵活和高效的操作方式。通过掌握切片的创建、访问、修改、遍历、动态增长、拷贝和删除等操作,开发者可以更高效地处理各种数据集合。

 

使用切片时需要注意以下几个重要点,以避免潜在的问题并提高代码的性能和可读性。

1. 切片的零值

切片的零值是 nil,一个 nil 切片的长度和容量都是 0。对一个 nil 切片进行追加操作是安全的。

package main

import "fmt"

func main() {
    var slice []int
    fmt.Println(slice == nil) // 输出:true
    slice = append(slice, 1, 2, 3)
    fmt.Println(slice) // 输出:[1 2 3]
}

package main

import "fmt"

func main() {
    var slice []int
    fmt.Println(slice == nil) // 输出:true
    slice = append(slice, 1, 2, 3)
    fmt.Println(slice) // 输出:[1 2 3]
}

package main

import "fmt"

func main() {
    slice := make([]int, 3, 5)
    fmt.Println("Length:", len(slice)) // 输出:3
    fmt.Println("Capacity:", cap(slice)) // 输出:5
}

3. 切片的共享底层数组

多个切片可以共享同一个底层数组。对一个切片的修改可能影响其他切片,因为它们引用的是同一个底层数组。

package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5}
    slice1 := arr[:]
    slice2 := arr[2:]
    slice2[0] = 100
    fmt.Println(slice1) // 输出:[1 2 100 4 5]
    fmt.Println(slice2) // 输出:[100 4 5]
}

4. 使用 append 时的注意事项

使用 append 向切片添加元素时,如果底层数组的容量不足以容纳新的元素,append 会创建一个新的数组并将旧数组的内容复制过去。因此,可能会发生切片的重新分配和复制操作。

package main

import "fmt"

func main() {
    slice := make([]int, 3, 5)
    fmt.Println("Before append: len =", len(slice), ", cap =", cap(slice))
    slice = append(slice, 4, 5, 6)
    fmt.Println("After append: len =", len(slice), ", cap =", cap(slice))
}

5. 切片的切片操作

对切片进行切片操作时,新切片仍然引用相同的底层数组。修改新切片的元素会影响原始切片。

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3, 4, 5}
    subSlice := slice[1:4]
    subSlice[0] = 100
    fmt.Println(slice) // 输出:[1 100 3 4 5]
    fmt.Println(subSlice) // 输出:[100 3 4]
}

6. 切片的深拷贝

如果需要创建一个切片的深拷贝,即独立于原始切片的一个新切片,可以使用 copy 函数。

package main

import "fmt"

func main() {
    source := []int{1, 2, 3}
    destination := make([]int, len(source))
    copy(destination, source)
    destination[0] = 100
    fmt.Println("Source slice:", source) // 输出:[1 2 3]
    fmt.Println("Destination slice:", destination) // 输出:[100 2 3]
}

7. 切片的内存管理

切片在处理大量数据时可能会导致内存泄漏,因为切片引用的底层数组不会被垃圾回收,即使切片本身已经不再使用。解决方法是明确切片和底层数组的关系,必要时手动释放不再使用的切片。

package main

import "fmt"

func main() {
    original := make([]int, 1000)
    // 创建一个小切片引用大数组
    smallSlice := original[:10]

    // 为了避免内存泄漏,可以创建一个新的切片并复制所需的部分
    copySmallSlice := make([]int, len(smallSlice))
    copy(copySmallSlice, smallSlice)
    fmt.Println("New small slice:", copySmallSlice)
}

8. 切片的边界检查

Go 语言会自动进行边界检查,以确保切片操作不会超出其范围。这种检查在运行时进行,如果访问越界,将会引发运行时恐慌(panic)。

package main

import "fmt"

func main() {
    slice := []int{1, 2, 3}
    fmt.Println(slice[2]) // 正常访问
    // fmt.Println(slice[3]) // 运行时恐慌:index out of range
}

9. 切片的零值行为

切片的零值行为是合理的,这意味着即使切片为 nil,也可以安全地对其执行操作,如追加元素或遍历。

package main

import "fmt"

func main() {
    var slice []int
    fmt.Println("Length:", len(slice)) // 输出:0
    fmt.Println("Capacity:", cap(slice)) // 输出:0
    slice = append(slice, 1, 2, 3)
    fmt.Println("After append:", slice) // 输出:[1 2 3]
}

 

posted @ 2024-07-08 23:48  JJJhr  阅读(4)  评论(0编辑  收藏  举报