切片的使用

package main

import "fmt"

func main() {
   // 定义一个长度为2的切片,其元素的数据类型为string
   var slice = make([]string, 2) // 等价于:var slice []string = make([]string, 2)
   slice[0] = "m"
   slice[1] = "a"

   // 也可以在定义切片时直接设置元素,这样就不需要使用make()函数
   // var slice = []string{"m", "a"}

   fmt.Printf("slice = %+v \n", slice)        // slice = [m a]
   fmt.Printf("slice长度 = %+v \n", len(slice)) // slice长度 = 2

   // 切片追加元素
   slice = append(slice, "n")
   slice = append(slice, "o")
   slice = append(slice, "n")
   slice = append(slice, "g")
   fmt.Printf("slice = %+v \n", slice)        // slice = [m a n o n g]
   fmt.Printf("slice长度 = %+v \n", len(slice)) // slice长度 = 6

   str := ""

   // 遍历切片,使用『for index, value := range 切片』方式,如果不需要使用索引编号“index”可以将其改为“_”
   for index, value := range slice {
      fmt.Printf("第%d个字母:%s \n", index, value)
      // 第0个字母:m
      // 第1个字母:a
      // 第2个字母:n
      // 第3个字母:o
      // 第4个字母:n
      // 第5个字母:g

      str += value
   }
   fmt.Printf("str = %+v \n", str) // str = manong
}

// ========== 总结 ========== //
// 1、切片可以粗略理解为可动态改变长度的数组(注:数组在定义时必须指定长度,且无法修改长度)。
// 2、遍历切片和遍历数组的方式是一样的,都可以通过『for index, value := range slice』来遍历,
//    如果不需要使用索引编号“index”可以将其改为“_”。
// 3、切片判空只能用len(slice)是否为0来判断,不能用slice是否为nil来判断。
// 4、切片与切片之间不能比较,即不能用==来判断两个切片是否相等。



  关于遍历结构体切片的坑

package main

import (
   "fmt"
)

type Human struct {
   Name  string
   Sex   string
   Birth int
}

func main() {
   slice := []Human{
      {Name: "张三", Sex: "男", Birth: 2003},
      {Name: "李四", Sex: "女", Birth: 2004},
      {Name: "王五", Sex: "男", Birth: 2005},
   }

   m := map[int]*Human{}

   // 遍历切片元素
   for index, value := range slice {
      m[index] = &value
   }
   // 重要说明:上面的遍历结构体切片元素代码是有问题的,value是临时变量,它保存的是结构体的值,而不是指针,
   //           并且在整个遍历过程中会一直复用,即每轮循环“m[index] = &value”都是在保存一个临时变量的指针,
   //           并不能把slice的数据转存到m里,当执行最后一轮循环时,slice最后一个元素的值会拷贝到value。

   fmt.Println(m) // map[0:0xc00010e180 1:0xc00010e180 2:0xc00010e180]
   // 重要说明:从打印结果可以清楚地看到,m的三个元素是同一个指针。

   // 遍历map元素
   for index, value := range m {
      fmt.Printf("map第%d个元素:%s %s %d \n", index, value.Name, value.Sex, value.Birth)
   }
   // map第1个元素:王五 男 2005
   // map第2个元素:王五 男 2005
   // map第0个元素:王五 男 2005
   // 重要说明:由于m的三个元素是同一个指针,所以打印出来的内容是完全一样的。
}

// ========== 总结 ========== //
// 1、上面代码问题的根源在于slice和m的valueType不一致,slice的valueType是Human,而m的valueType是*Human,
//    即一个是结构体,一个是结构体指针。解决问题的办法也很简单,把slice和m的valueType改为相同的即可,
//    可以两个都改为Human,或者两个都改为*Human,一般来说建议使用*Human。
//    操作结构体建议使用指针,而不是结构体本身,因为将结构体指针作为参数传递不会发生值拷贝故而效率更高,
//    并且也可以避免因为值拷贝导致的稀奇古怪的问题。

Copyright © 2025 码农人生. All Rights Reserved