切片底层

1. 切片

切片,动态数组。

切片是Go中重要的数据类型,每个切片对象内部都维护着:数组指针、切片长度、切片容量 三个数据。

type slice struct {
  array unsafe.Pointer
  len   int
  cap   int

在向切片中追加的数据个数大于容量时,内部会自动扩容且每次扩容都当前容量的2倍(当容量超过1024时每次扩容则只增加 1/4容量)。

1.1. 创建切片

// 创建切片
var nums []int// 创建切片
var data = []int{11,22,33}
data:= []int{11,22,33}
​
// 创建切片
// make只用于 切片、字典、channel
var users = make([]int,1,3)
// 切片的指针类型
var v1 = new([]int)
​
// 指针类型(nil)
var v2 *[]int

1.2. 自动扩容

v1 := make([]int,1,3)
​
fmt.Println(len(v1),cap(v1))
​
// 其他
data := make([]int,3)
v1 := make([]int,1,3)
​
v2 := append(v1,66)
​
fmt.Println(v1)  // [0 ]
fmt.Println(v2)  // [0,66]
​
v1[0] = 999
fmt.Println(v1)  // [999 ]
fmt.Println(v2)  // [999,66]// 需求:有一个切片,请往一个切片中追加一个数据。
v3 := make([]int,1,3)
v3 = append(v3,999)
v1 := []int{11,22,33}
v2 := append(v1,44)
​
v1[0] = 999
​
fmt.Println(v1) // [999 22 33]
fmt.Println(v2) // [11 22 33 44]

2. 常见操作

1 长度和容量

v1 := []int{11,22,33}
fmt.Println(len(v1), cap(v1))

2 索引

v1 := []string{"alex","李杰","老男孩"}
v1[0]
v1[1]
v1[2]
​
v2 := make([]int,2,5)
v2[0]
v2[1]
v2[2]  // 报错
​
​
v2[0] = 999

3 切片

v1 := []int{11,22,33,44,55,66}
​
v2 := v1[1:3]
v3 := v1[1:]
v4 := v1[:3]
​
// 注意:通过切片切出来的数据和原切片内部存储的数据地址相同

4 追加

package main
​
import (
  "fmt"
)
​
func main() {
  v1 := []int{11,22,33}
​
  v2 := append(v1,44)
​
  v3 := append(v1,55,66,77,88)
​
  v4 := append(v1, []int{100,200,300}...)
​
  fmt.Println(v2)
  fmt.Println(v3)
  fmt.Println(v4)
}
​
>>> 输出
[11 22 33 44]
[11 22 33 55 66 77 88]
[11 22 33 100 200 300]

5 删除

package main
​
import "fmt"func main() {
  v1 := []int{11, 22, 33, 44, 55, 66}
  deleteIndex := 2// 切片获取到 {11,22,44、55、66}
  // 又获取到 {44, 55, 66},将44、55、66要追加到
  result := append(v1[:deleteIndex], v1[deleteIndex+1:]...)
  fmt.Println(result) // [11 22 44 55 66]
  fmt.Println(v1)     //[11 22 44 55 66 66]
}

注意:使用切片时不太会使用删除。【链表】

6 插入

package main
​
import "fmt"func main() {
  v1 := []int{11, 22, 33, 44, 55, 66}
  insertIndex := 3 // 在索引3的位置插入99
​
  result := make([]int, 0, len(v1)+1)
  result = append(result, v1[:insertIndex]...)
  result = append(result,99)
  result = append(result,v1[insertIndex:]...)
  fmt.Println(result)
}

注意:效率低下。【链表】

7 循环

package main
​
import "fmt"func main() {
  v1 := []int{11, 22, 33, 99, 55, 66}
​
  for i := 0; i < len(v1); i++ {
    fmt.Println(i, v1[i])
  }
​
  for index, value := range v1 {
    fmt.Println(index, value)
  }
}

3. 切片嵌套

package main
​
import "fmt"func main() {
  v1 := []int{11, 22, 33, 99, 55, 66}
  v2 := [][]int{[]int{11, 22, 33, 44}, []int{44, 55}}
  v3 := [][2]int{[2]int{1, 2}, [2]int{4, 5}}
​
  fmt.Println(v1)
  fmt.Println(v2)
  fmt.Println(v3)
​
  v1[0] = 111111
  v2[0][2] = 222222
  v3[1][0] = 99999
​
  fmt.Println(v1)
  fmt.Println(v2)
  fmt.Println(v3)
}

4. 变量赋值

  • 整型

    package main
    ​
    import "fmt"func main() {
      v1 := 1
      v2 := v1
    ​
      fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000b4008
      fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000b4010
    }
    
  • 布尔类型

    package main
    ​
    import "fmt"func main() {
      v1 := false
      v2 := v1
    ​
      fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc00012a002
      fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc00012a003
    }
    
  • 浮点型

    package main
    ​
    import "fmt"func main() {
      v1 := 3.14
      v2 := v1
    ​
      fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc000016050
      fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc000016058
    }
    
  • 字符串

    package main
    ​
    import "fmt"func main() {
      v1 := "武沛齐"
      v2 := v1
    ​
      fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc000010200
      fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc000010210 
    }
    

    注意:字符串内部元素不可被修改。

  • 数组

    package main
    ​
    import "fmt"func main() {
      v1 := [2]int{6, 9}
      v2 := v1
      fmt.Println(v1, v2)
      fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000b4010
      fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000b4020
    ​
      v1[0] = 11111
      fmt.Println(v1, v2)
    }
    
  • 切片

    package main
    ​
    import "fmt"func main() {
      v1 := []int{6, 9}
      v2 := v1
      fmt.Println(v1, v2)              // [6 9] [6 9]
      fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000a6020
      fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000a6040
    ​
      v1[0] = 11111
      fmt.Println(v1, v2) // [11111 9] [11111 9]
    }
    

    如果扩容,那么内部存储数据的数组就会重新开辟区域。

    package main
    ​
    import "fmt"func main() {
      v1 := []int{6, 9}
      v2 := v1
      fmt.Println(v1, v2)              // [6 9] [6 9]
      fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000a6020
      fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000a6040
    ​
      v1 = append(v1, 999)
      fmt.Println(v1, v2) // [11111 9] [11111 9]
    }
    

总结,目前所学的所有的数据类型中,在修改切片的内部元素时,会造成所有的赋值的变量同时修改(不扩容)。

扩展:引用类型和值类型。go

\

1:

results matching ""

    No results matching ""