当前位置:   article > 正文

golang学习笔记——数组与切片_为什么slice addr和slice[0]相同

为什么slice addr和slice[0]相同

数组

*go中数组是值类型,数组作为参数时是进行的值拷贝

数组创建方式:

  1. package main
  2. import "fmt"
  3. func main() {
  4. //数组定义方式
  5. //数组的长度必须为数值常量
  6. var arr [3]int
  7. //var i int = 0
  8. //var ai [i]int
  9. arr[0] = 1
  10. arr[1] = 10
  11. arr[2] = 22
  12. fmt.Println(arr)
  13. var arr2 = [3]int{2, 4, 6}
  14. fmt.Println(arr2)
  15. //有编译器自动识别数组长度
  16. var arr3 = [...]int{5, 7, 8}
  17. fmt.Println(arr3)
  18. //可以定义空数组,但无实际价值
  19. arr4 := [...]int{}
  20. fmt.Println("arr4 len:", len(arr4))
  21. //arr4[0] = 0 //编译报错,下标越界
  22. //指定下标和对应的值
  23. arr5 := [3]int{0:9, 1:8, 2:7}
  24. fmt.Println("arr5 ", arr5)
  25. arr6 := [...]int{4:101}
  26. fmt.Println("arr6", arr6)
  27. //new 为内建函数 返回值为对应指针
  28. arr7Point := new([3]int)
  29. fmt.Printf("arr7Point type %T \n", arr7Point)
  30. (*arr7Point)[0] = 256
  31. (*arr7Point)[1] = 26
  32. (*arr7Point)[2] = 356
  33. fmt.Printf("*arr7Poiont %v ; len= %v \n", *arr7Point, len(*arr7Point))
  34. }

*数组的指针指向的是数组第一个元素的地址,即数组的指针==数组第一个元素的指针

*go中同数据类型元素的不同长度的数组认为非同类型数组

*通过for 或 for - range遍历数组

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. arr1 := [4]int{1, 2, 3, 4}
  7. fmt.Printf("arr1 address -- %p , arr1[0] address -- %p \n", &arr1, &arr1[0])
  8. //通过指针可以计算对应元素的位置
  9. //64位os,int为64位即8个字节,数组内存是连续的,
  10. //arr1[0]的地址加8字节即为arr[1]的位置
  11. fmt.Printf("arr1[0] address -- %p, arr1[1] address -- %p \n", &arr1[0], &arr1[1])
  12. arr2 := [...]int{1, 2}
  13. foreachLen4(arr1)
  14. fmt.Println(arr1)
  15. foreachLen2(arr2)
  16. //foreachLen2(arr1) //编译报错
  17. //foreachLen4(arr2) //编译报错
  18. }
  19. func foreachLen4(arr [4]int) {
  20. for i := 0; i < len(arr); i++ {
  21. fmt.Println("foreachLen4 - ", arr[i])
  22. //go中数组为值类型 进行值拷贝
  23. arr[i] = arr[i] + 1
  24. }
  25. }
  26. func foreachLen2(arr [2]int) {
  27. //range 可将数组下标和对应的值返回, 通过下划线 可以忽略 下标或值
  28. // for _, val := range arr
  29. // for idx, _ := range arr
  30. for idx, val := range arr {
  31. fmt.Printf("foreachLen2: idx -- %v, val -- %v \n", idx, val)
  32. }
  33. }

 

切片slice

*go中特有的数据类型切片类似可变数组,切片持有对应数组的元素指针

  1. package main
  2. import "fmt"
  3. func main() {
  4. //指针的创建
  5. var arr [5]int = [5]int{1, 2, 3, 4, 5}
  6. //从数组映射 数组[起始下标 : 截止下标], 含头不含尾
  7. //注意[]int中“[]”无数字
  8. var slice []int= arr[1:3]
  9. fmt.Println("slice ", slice)
  10. //当起始下标为0 ,或截止下标为对应数组长度时可省略
  11. slice2 := arr[:3]
  12. slice3 := arr[1:]
  13. slice4 := arr[:]
  14. fmt.Println("slice2: ", slice2, " slice3: ", slice3, " slice4:", slice4)
  15. //切片中的元素对应映射数组元素的指针
  16. fmt.Printf("arr addr -- %p, arr[1] addr -- %p , arr[2] addr -- %p \n",
  17. &arr, &arr[1], &arr[2])
  18. fmt.Printf("slice addr -- %p, slice[0] addr -- %p, slice[1] addr -- %p \n ",
  19. &slice[0], &slice[1])
  20. //make 为内建函数,创建应用类型
  21. //make(切片类型, 初始长度, 初始容量)
  22. slice5 := make([]int, 3, 6)
  23. slice5[0] = 99
  24. slice5[1] = 88
  25. slice5[2] = 77
  26. //切片有长度 与 容量属性,容量随元素个数的增加而自动扩充,内建函数cap可获得容量
  27. fmt.Printf("slice5 len %v , cap %v", len(slice5), cap(slice5))
  28. fmt.Println("slice5", slice5)
  29. //切片虽为可变长,但增加超过初始长度的元素时不可通过下标直接赋值,需使用内建函数append
  30. // slice5[3] = 66 //编译报错 越界
  31. //append 会返回扩充后的切片
  32. slice5 = append(slice5, 66)
  33. fmt.Println("slice5 --", slice5)
  34. //可以append对应类型切片,但不可append数组 ==》类型不匹配
  35. slice5 = append(slice5, slice...)
  36. // slice5 = append(slice5, arr...) //编译报错
  37. fmt.Println("slice5 ** ", slice5)
  38. }

切片扩容

  1. package main
  2. import (
  3. "math/rand"
  4. "time"
  5. "fmt"
  6. )
  7. func main() {
  8. slice := make([]int, 5, 10)
  9. //slice 是引用类型
  10. generate(slice)
  11. fmt.Println("slice ", slice)
  12. arr := [5]int{1, 2, 3, 4, 5}
  13. slice2 := arr[:]
  14. fmt.Println("slice2: ", slice2, "arr ", arr)
  15. fmt.Println("slice2 addr: ", &slice2, "arr addr:", &arr)
  16. generate(slice2)
  17. //切片是数组元素的引用,故切片改变会导致原数组改变,反过来也是
  18. //虽然元素对应的值发生变化,但元素对应的指针并未发生变化
  19. //(开辟的空间可以存放对应的数据类型)
  20. //切片可以理解成是由 对应数组元素的指针组成的数组 + 长度属性 + 容量属性 的结构
  21. fmt.Println("slice2 -- ", slice2, "arr -- ", arr)
  22. fmt.Println("slice2 --addr ", &slice2, "arr --addr ", &arr)
  23. fmt.Printf("arr len %v , slice2 len %v \n",
  24. len(arr), len(slice2))
  25. //append带来的改变
  26. slice3 := append(slice2, 6)
  27. fmt.Printf("arr add - %p, slice2 add - %p, slice3 add - %p \n",
  28. &arr, &slice2, &slice3)
  29. //append 是将原有切片对应的元素的值拷贝到新的地址,故而新切片元素对应的指针发生改变
  30. //append是重新分配内存空间
  31. fmt.Printf("arr len %v , slice2 len %v, slice3 len %v \n",
  32. len(arr), len(slice2), len(slice3))
  33. fmt.Printf("arr[1] add %p, slice2[1] add %p, slice3[1] add %p \n",
  34. &arr[1], &slice2[1], &slice3[1])
  35. }
  36. func generate(slice []int) {
  37. //设置随机因子
  38. rand.Seed(time.Now().UnixNano())
  39. for i := 0; i < 5; i++ {
  40. slice[i] = rand.Intn(100)
  41. }
  42. }

切片append与切片容量

*一个大坑:

*通过数组映射过来的切片长度与容量一致,make声明切片时可省略容量此时默认容量与长度一致;

*切片append所返回的新切片会共用原切片所定义的容量范围内的空间,即在append的元素不超过设定的容量时,新的切片元素的指针与原有切片元素的指针 指向的是同一个地址,当超出容量时则指向不同的地址

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. //容量
  7. arr := [3]int{1, 2, 3}
  8. s := arr[:]
  9. fmt.Println("s = ", s, " len ", len(s), " cap ", cap(s))
  10. s1 := make([]int, 3)
  11. fmt.Println("s1 = ", s1, " len ", len(s1), " cap ", cap(s1))
  12. fmt.Println("-----------------------------")
  13. //
  14. slice := make([]int, 2, 3)
  15. slice[0] = 8
  16. slice[1] = 88
  17. fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p \n", &slice, &slice[0], &slice[1])
  18. fmt.Println("-----------slice append 9 ==> slice2------------------")
  19. slice2 := append(slice, 9)
  20. fmt.Println("slice = ", slice, " len ", len(slice), " cap ", cap(slice))
  21. fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p \n", &slice, &slice[0], &slice[1])
  22. fmt.Println("slice2 = ", slice2, " len ", len(slice2), " cap ", cap(slice2))
  23. fmt.Printf("slice2地址:%p slice2[0]地址:%p slice2[1]地址:%p slice2[1]地址:%p \n",
  24. &slice2, &slice2[0], &slice2[1], &slice2[2])
  25. //slice2 append超过 slice 的容量时 slice2元素的地址就与slice不一致
  26. // fmt.Println("-----------slice2 append ==> slice2------------------")
  27. // slice2 = append(slice2, 99)
  28. // fmt.Println("slice = ", slice)
  29. // fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p \n", &slice, &slice[0], &slice[1])
  30. // fmt.Println("slice2 = ", slice2)
  31. // fmt.Printf("slice2地址:%p slice2[0]地址:%p slice2[1]地址:%p slice2[2]地址:%p slice2[3]地址:%p\n",
  32. // &slice2, &slice2[0], &slice2[1], &slice2[2], &slice2[3])
  33. fmt.Println("-----------slice append 100 ==> slice------------------")
  34. slice = append(slice, 100)
  35. fmt.Println("slice = ", slice, " len ", len(slice), " cap ", cap(slice))
  36. fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p slice[2]地址:%p \n",
  37. &slice, &slice[0], &slice[1], &slice[2])
  38. fmt.Println("slice2 = ", slice2, " len ", len(slice2), " cap ", cap(slice2))
  39. fmt.Printf("slice2地址:%p slice2[0]地址:%p slice2[1]地址:%p slice2[2]地址:%p \n",
  40. &slice2, &slice2[0], &slice2[1], &slice2[2])
  41. fmt.Println("-----------slice append 20 ==> slice-----超过容量-------------")
  42. slice = append(slice, 20)
  43. fmt.Println("slice = ", slice, " len ", len(slice), " cap ", cap(slice))
  44. fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p slice[2]地址:%p slice[3]地址:%p \n",
  45. &slice, &slice[0], &slice[1], &slice[2], &slice[3])
  46. fmt.Println("slice2 = ", slice2, " len ", len(slice2), " cap ", cap(slice2))
  47. fmt.Printf("slice2地址:%p slice2[0]地址:%p slice2[1]地址:%p slice2[2]地址:%p \n",
  48. &slice2, &slice2[0], &slice2[1], &slice2[2])
  49. }

string 与切片以及rune

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. //string 底层是byte数组,且该数组不可变
  7. str := "hello,独角兽!"
  8. fmt.Println(str)
  9. strSlice := str[:5]
  10. fmt.Println("截取:", strSlice)
  11. //因string对应的byte数组不可变,故而str对应的切片中的元素也不可以重新赋值
  12. // strSlice[0] = 'A'
  13. //通过byte数组来改变
  14. bytes := []byte(str)
  15. bytes[0] = 'A'
  16. newStr := string(bytes)
  17. fmt.Println("str -- ", str, " newStr --", newStr)
  18. //因go为utf8编码,byte对应一个字节,汉字为三个字节,无法放入单个字节
  19. //rune的定义:32位有符号整形,int32的别名;将string转换成rune数组时
  20. //解决了汉字长度的问题
  21. // bytes[0] = '我'
  22. //rune 按照字符处理string
  23. strRune := []rune(str)
  24. strRune[0] = '我'
  25. newStr = string(strRune)
  26. fmt.Println(newStr)
  27. }

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/206435
推荐阅读
相关标签
  

闽ICP备14008679号