Golang入门教程9:切片 -- 轻松应对动态数据集

生活中,打造完美的家庭聚餐

假设你在准备一个周末家庭聚餐,想要为家人做一道美味的菜。这个时候,可以将Golang的切片概念与食材选择相结合。

  1. 切片的定义: 就像你在做菜时选择合适的食材一样,Golang中的切片就像一个动态数组,允许你根据需要动态地调整大小。

  2. 创建切片: 想象你在准备沙拉,初始时可能有很多蔬菜,但你不确定需要多少。Golang切片的创建方式也是类似的,不需要预先指定大小。

    go 复制代码
    salad := []string{"lettuce", "tomato", "cucumber", "carrot"}
  3. 切片的追加和删除: 当你决定在沙拉中加入一种新的食材,或者有人不喜欢某一种,你可以随时追加或删除。

    go 复制代码
    // 追加新食材
    salad = append(salad, "bell pepper")
    
    // 删除不喜欢的食材
    salad = append(salad[:2], salad[3:]...)
  4. 切片的动态性: 正如你在调整菜谱时可以随时添加或去除食材,Golang切片的动态性允许你在程序运行时动态调整大小,适应不同的需求。

  5. 共享底层数组: 多个人共享同一盘沙拉,类似地,多个切片可以共享相同的底层数组。如果你在切片中添加或删除元素,底层数组会被修改,影响到所有共享的切片。

通过这个生活中的比喻,希望你可以更好地理解Golang中切片的概念,以及它如何在程序中灵活地处理数据。

Golang中的切片

切片(Slice)是Go语言中一个重要而强大的数据结构,用于处理序列化的数据集合。切片提供了对数组的抽象,使得在处理集合数据时更加灵活和便捷。以下是关于切片的核心概念:

  1. 定义: 切片是对数组的一层封装,它指向数组的某个部分,并且包含了三个重要的属性:指针、长度和容量。

  2. 指针(Pointer): 切片包含一个指针,指向数组中的第一个元素。这意味着切片的起始位置是数组的某个位置。

  3. 长度(Length): 切片的长度表示它包含的元素数量,即切片的实际大小。

  4. 容量(Capacity): 切片的容量是指从切片的起始位置到底层数组末尾的元素数量。容量决定了切片的最大大小。

  5. 创建切片: 可以使用切片表达式创建一个切片,例如 arr[low:high],其中 low 是起始索引,high 是结束索引(不包含)。

    go 复制代码
    arr := []int{1, 2, 3, 4, 5}
    slice := arr[1:4]  // 创建一个包含 arr[1], arr[2], arr[3] 的切片
  6. 切片的动态性: 切片是动态的,可以在运行时修改长度,从而实现动态数组的效果。

    go 复制代码
    slice = append(slice, 6)  // 在切片末尾添加元素
  7. 共享底层数组: 多个切片可以共享相同的底层数组,一个切片的修改会影响到其他共享底层数组的切片。

    go 复制代码
    arr := []int{1, 2, 3, 4, 5}
    slice1 := arr[1:4]
    slice2 := arr[2:5]
    
    slice1[0] = 99
    fmt.Println(arr)  // 输出 [1 99 3 4 5]

切片的灵活性使得在处理数据集时更加方便,同时由于切片是引用类型,它的传递不会复制底层数组,减少了内存开销。切片在Go语言中广泛用于处理动态数据集,如切片、映射等。

实践

这段Go代码演示了切片(slice)的基本操作和特性。以下是对代码的解释:

  1. 未初始化的切片:

    go 复制代码
    var s []string
    fmt.Println("uninit:", s, s == nil, len(s) == 0)

    创建一个未初始化的切片 s,打印切片内容、是否为 nil 以及长度是否为0。因为切片未初始化,所以内容为空,判断为 nil,长度为0。

  2. 使用 make 创建切片:

    go 复制代码
    s = make([]string, 3)
    fmt.Println("emp:", s, "len:", len(s), "cap:", cap(s))

    使用 make 函数创建一个长度为3的切片 s,打印切片内容、长度和容量。此时切片内容为零值(字符串的零值为""),长度为3,容量也为3。

  3. 切片赋值和访问:

    go 复制代码
    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("set:", s)
    fmt.Println("get:", s[2])

    对切片进行赋值和访问。切片的索引从0开始,通过索引访问和设置元素。

  4. 使用 append 添加元素:

    go 复制代码
    s = append(s, "d")
    s = append(s, "e", "f")
    fmt.Println("apd:", s)

    使用 append 函数向切片追加元素。append 函数可以一次追加多个元素。

  5. 复制切片:

    go 复制代码
    c := make([]string, len(s))
    copy(c, s)
    fmt.Println("cpy:", c)

    使用 make 创建一个与切片 s 相同长度的新切片 c,然后使用 copy 函数将 s 复制到 c

  6. 切片操作:

    go 复制代码
    l := s[2:5]
    fmt.Println("sl1:", l)
    
    l = s[:5]
    fmt.Println("sl2:", l)
    
    l = s[2:]
    fmt.Println("sl3:", l)

    演示切片操作,包括从索引2截取到索引5,从头截取到索引5,从索引2截取到末尾。

  7. 切片的声明和比较:

    go 复制代码
    t := []string{"g", "h", "i"}
    fmt.Println("dcl:", t)
    
    t2 := []string{"g", "h", "i"}
    if slices.Equal(t, t2) {
        fmt.Println("t == t2")
    }

    使用简短声明语法创建切片 t,并比较两个切片是否相等。

  8. 二维切片:

    go 复制代码
    twoD := make([][]int, 3)
    for i := 0; i < 3; i++ {
        innerLen := i + 1
        twoD[i] = make([]int, innerLen)
        for j := 0; j < innerLen; j++ {
            twoD[i][j] = i + j
            fmt.Printf("i=%d j=%d\n", i, j)
        }
    }
    fmt.Println("2d:", twoD)

    创建一个二维切片 twoD,演示如何动态创建不同长度的切片,并为其赋值。最后打印二维切片的内容。

    完整示例代码:

go 复制代码
package main

import (
   "fmt"
   "golang.org/x/exp/slices"
)

func main() {
   var s []string
   fmt.Println("uninit:", s, s == nil, len(s) == 0)

   s = make([]string, 3)
   fmt.Println("emp:", s, "len:", len(s), "cap:", cap(s))

   s[0] = "a"
   s[1] = "b"
   s[2] = "c"
   fmt.Println("set:", s)
   fmt.Println("get:", s[2])

   fmt.Println("len:", len(s))

   s = append(s, "d")
   s = append(s, "e", "f")
   fmt.Println("apd:", s)

   c := make([]string, len(s))
   copy(c, s)
   fmt.Println("cpy:", c)

   l := s[2:5]
   fmt.Println("sl1:", l)

   l = s[:5]
   fmt.Println("sl2:", l)

   l = s[2:]
   fmt.Println("sl3:", l)

   t := []string{"g", "h", "i"}
   fmt.Println("dcl:", t)

   t2 := []string{"g", "h", "i"}
   if slices.Equal(t, t2) {
      fmt.Println("t == t2")
   }

   twoD := make([][]int, 3)
   for i := 0; i < 3; i++ {
      innerLen := i + 1
      twoD[i] = make([]int, innerLen)
      for j := 0; j < innerLen; j++ {
         twoD[i][j] = i + j
         fmt.Printf("i=%d j=%d\n", i, j)
      }
   }
   fmt.Println("2d:", twoD)
}   
相关推荐
假装我不帅36 分钟前
asp.net framework从webform开始创建mvc项目
后端·asp.net·mvc
神仙别闹39 分钟前
基于ASP.NET+SQL Server实现简单小说网站(包括PC版本和移动版本)
后端·asp.net
计算机-秋大田1 小时前
基于Spring Boot的船舶监造系统的设计与实现,LW+源码+讲解
java·论文阅读·spring boot·后端·vue
货拉拉技术1 小时前
货拉拉-实时对账系统(算盘平台)
后端
掘金酱2 小时前
✍【瓜分额外奖金】11月金石计划附加挑战赛-活动命题发布
人工智能·后端
代码之光_19802 小时前
保障性住房管理:SpringBoot技术优势分析
java·spring boot·后端
ajsbxi2 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
架构师那点事儿3 小时前
golang 用unsafe 无所畏惧,但使用不得到会panic
架构·go·掘金技术征文
颜淡慕潇3 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
尘浮生4 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea