赞
踩
数组:
*go中数组是值类型,数组作为参数时是进行的值拷贝
数组创建方式:
- package main
-
- import "fmt"
-
- func main() {
- //数组定义方式
-
- //数组的长度必须为数值常量
- var arr [3]int
- //var i int = 0
- //var ai [i]int
- arr[0] = 1
- arr[1] = 10
- arr[2] = 22
- fmt.Println(arr)
-
- var arr2 = [3]int{2, 4, 6}
- fmt.Println(arr2)
-
- //有编译器自动识别数组长度
- var arr3 = [...]int{5, 7, 8}
- fmt.Println(arr3)
- //可以定义空数组,但无实际价值
- arr4 := [...]int{}
- fmt.Println("arr4 len:", len(arr4))
- //arr4[0] = 0 //编译报错,下标越界
-
- //指定下标和对应的值
- arr5 := [3]int{0:9, 1:8, 2:7}
- fmt.Println("arr5 ", arr5)
- arr6 := [...]int{4:101}
- fmt.Println("arr6", arr6)
-
- //new 为内建函数 返回值为对应指针
- arr7Point := new([3]int)
- fmt.Printf("arr7Point type %T \n", arr7Point)
- (*arr7Point)[0] = 256
- (*arr7Point)[1] = 26
- (*arr7Point)[2] = 356
- fmt.Printf("*arr7Poiont %v ; len= %v \n", *arr7Point, len(*arr7Point))
- }
*数组的指针指向的是数组第一个元素的地址,即数组的指针==数组第一个元素的指针
*go中同数据类型元素的不同长度的数组认为非同类型数组
*通过for 或 for - range遍历数组
- package main
-
- import (
- "fmt"
- )
-
- func main() {
- arr1 := [4]int{1, 2, 3, 4}
- fmt.Printf("arr1 address -- %p , arr1[0] address -- %p \n", &arr1, &arr1[0])
- //通过指针可以计算对应元素的位置
- //64位os,int为64位即8个字节,数组内存是连续的,
- //arr1[0]的地址加8字节即为arr[1]的位置
- fmt.Printf("arr1[0] address -- %p, arr1[1] address -- %p \n", &arr1[0], &arr1[1])
- arr2 := [...]int{1, 2}
-
- foreachLen4(arr1)
- fmt.Println(arr1)
- foreachLen2(arr2)
- //foreachLen2(arr1) //编译报错
- //foreachLen4(arr2) //编译报错
- }
-
- func foreachLen4(arr [4]int) {
- for i := 0; i < len(arr); i++ {
- fmt.Println("foreachLen4 - ", arr[i])
- //go中数组为值类型 进行值拷贝
- arr[i] = arr[i] + 1
- }
- }
-
- func foreachLen2(arr [2]int) {
- //range 可将数组下标和对应的值返回, 通过下划线 可以忽略 下标或值
- // for _, val := range arr
- // for idx, _ := range arr
- for idx, val := range arr {
- fmt.Printf("foreachLen2: idx -- %v, val -- %v \n", idx, val)
- }
- }
-
切片slice
*go中特有的数据类型切片类似可变数组,切片持有对应数组的元素指针
- package main
-
- import "fmt"
-
- func main() {
- //指针的创建
- var arr [5]int = [5]int{1, 2, 3, 4, 5}
- //从数组映射 数组[起始下标 : 截止下标], 含头不含尾
- //注意[]int中“[]”无数字
- var slice []int= arr[1:3]
- fmt.Println("slice ", slice)
- //当起始下标为0 ,或截止下标为对应数组长度时可省略
- slice2 := arr[:3]
- slice3 := arr[1:]
- slice4 := arr[:]
- fmt.Println("slice2: ", slice2, " slice3: ", slice3, " slice4:", slice4)
-
- //切片中的元素对应映射数组元素的指针
- fmt.Printf("arr addr -- %p, arr[1] addr -- %p , arr[2] addr -- %p \n",
- &arr, &arr[1], &arr[2])
- fmt.Printf("slice addr -- %p, slice[0] addr -- %p, slice[1] addr -- %p \n ",
- &slice[0], &slice[1])
-
- //make 为内建函数,创建应用类型
- //make(切片类型, 初始长度, 初始容量)
- slice5 := make([]int, 3, 6)
- slice5[0] = 99
- slice5[1] = 88
- slice5[2] = 77
-
- //切片有长度 与 容量属性,容量随元素个数的增加而自动扩充,内建函数cap可获得容量
- fmt.Printf("slice5 len %v , cap %v", len(slice5), cap(slice5))
-
- fmt.Println("slice5", slice5)
- //切片虽为可变长,但增加超过初始长度的元素时不可通过下标直接赋值,需使用内建函数append
- // slice5[3] = 66 //编译报错 越界
- //append 会返回扩充后的切片
- slice5 = append(slice5, 66)
- fmt.Println("slice5 --", slice5)
- //可以append对应类型切片,但不可append数组 ==》类型不匹配
- slice5 = append(slice5, slice...)
- // slice5 = append(slice5, arr...) //编译报错
- fmt.Println("slice5 ** ", slice5)
- }
切片扩容
- package main
-
- import (
- "math/rand"
- "time"
- "fmt"
- )
-
- func main() {
- slice := make([]int, 5, 10)
- //slice 是引用类型
- generate(slice)
- fmt.Println("slice ", slice)
-
- arr := [5]int{1, 2, 3, 4, 5}
- slice2 := arr[:]
- fmt.Println("slice2: ", slice2, "arr ", arr)
- fmt.Println("slice2 addr: ", &slice2, "arr addr:", &arr)
- generate(slice2)
- //切片是数组元素的引用,故切片改变会导致原数组改变,反过来也是
- //虽然元素对应的值发生变化,但元素对应的指针并未发生变化
- //(开辟的空间可以存放对应的数据类型)
- //切片可以理解成是由 对应数组元素的指针组成的数组 + 长度属性 + 容量属性 的结构
- fmt.Println("slice2 -- ", slice2, "arr -- ", arr)
- fmt.Println("slice2 --addr ", &slice2, "arr --addr ", &arr)
- fmt.Printf("arr len %v , slice2 len %v \n",
- len(arr), len(slice2))
- //append带来的改变
- slice3 := append(slice2, 6)
- fmt.Printf("arr add - %p, slice2 add - %p, slice3 add - %p \n",
- &arr, &slice2, &slice3)
- //append 是将原有切片对应的元素的值拷贝到新的地址,故而新切片元素对应的指针发生改变
- //append是重新分配内存空间
- fmt.Printf("arr len %v , slice2 len %v, slice3 len %v \n",
- len(arr), len(slice2), len(slice3))
- fmt.Printf("arr[1] add %p, slice2[1] add %p, slice3[1] add %p \n",
- &arr[1], &slice2[1], &slice3[1])
-
-
- }
-
- func generate(slice []int) {
- //设置随机因子
- rand.Seed(time.Now().UnixNano())
- for i := 0; i < 5; i++ {
- slice[i] = rand.Intn(100)
- }
- }
切片append与切片容量
*一个大坑:
*通过数组映射过来的切片长度与容量一致,make声明切片时可省略容量此时默认容量与长度一致;
*切片append所返回的新切片会共用原切片所定义的容量范围内的空间,即在append的元素不超过设定的容量时,新的切片元素的指针与原有切片元素的指针 指向的是同一个地址,当超出容量时则指向不同的地址
- package main
-
- import (
- "fmt"
- )
-
- func main() {
- //容量
- arr := [3]int{1, 2, 3}
- s := arr[:]
- fmt.Println("s = ", s, " len ", len(s), " cap ", cap(s))
-
- s1 := make([]int, 3)
- fmt.Println("s1 = ", s1, " len ", len(s1), " cap ", cap(s1))
- fmt.Println("-----------------------------")
-
- //
- slice := make([]int, 2, 3)
- slice[0] = 8
- slice[1] = 88
- fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p \n", &slice, &slice[0], &slice[1])
-
- fmt.Println("-----------slice append 9 ==> slice2------------------")
- slice2 := append(slice, 9)
- fmt.Println("slice = ", slice, " len ", len(slice), " cap ", cap(slice))
- fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p \n", &slice, &slice[0], &slice[1])
- fmt.Println("slice2 = ", slice2, " len ", len(slice2), " cap ", cap(slice2))
- fmt.Printf("slice2地址:%p slice2[0]地址:%p slice2[1]地址:%p slice2[1]地址:%p \n",
- &slice2, &slice2[0], &slice2[1], &slice2[2])
-
- //slice2 append超过 slice 的容量时 slice2元素的地址就与slice不一致
- // fmt.Println("-----------slice2 append ==> slice2------------------")
- // slice2 = append(slice2, 99)
- // fmt.Println("slice = ", slice)
- // fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p \n", &slice, &slice[0], &slice[1])
- // fmt.Println("slice2 = ", slice2)
- // fmt.Printf("slice2地址:%p slice2[0]地址:%p slice2[1]地址:%p slice2[2]地址:%p slice2[3]地址:%p\n",
- // &slice2, &slice2[0], &slice2[1], &slice2[2], &slice2[3])
-
- fmt.Println("-----------slice append 100 ==> slice------------------")
- slice = append(slice, 100)
- fmt.Println("slice = ", slice, " len ", len(slice), " cap ", cap(slice))
- fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p slice[2]地址:%p \n",
- &slice, &slice[0], &slice[1], &slice[2])
- fmt.Println("slice2 = ", slice2, " len ", len(slice2), " cap ", cap(slice2))
- fmt.Printf("slice2地址:%p slice2[0]地址:%p slice2[1]地址:%p slice2[2]地址:%p \n",
- &slice2, &slice2[0], &slice2[1], &slice2[2])
-
- fmt.Println("-----------slice append 20 ==> slice-----超过容量-------------")
- slice = append(slice, 20)
- fmt.Println("slice = ", slice, " len ", len(slice), " cap ", cap(slice))
- fmt.Printf("slice地址:%p slice[0]地址:%p slice[1]地址:%p slice[2]地址:%p slice[3]地址:%p \n",
- &slice, &slice[0], &slice[1], &slice[2], &slice[3])
- fmt.Println("slice2 = ", slice2, " len ", len(slice2), " cap ", cap(slice2))
- fmt.Printf("slice2地址:%p slice2[0]地址:%p slice2[1]地址:%p slice2[2]地址:%p \n",
- &slice2, &slice2[0], &slice2[1], &slice2[2])
-
-
- }
string 与切片以及rune
- package main
-
- import (
- "fmt"
- )
-
- func main() {
- //string 底层是byte数组,且该数组不可变
- str := "hello,独角兽!"
- fmt.Println(str)
- strSlice := str[:5]
- fmt.Println("截取:", strSlice)
- //因string对应的byte数组不可变,故而str对应的切片中的元素也不可以重新赋值
- // strSlice[0] = 'A'
-
- //通过byte数组来改变
- bytes := []byte(str)
- bytes[0] = 'A'
- newStr := string(bytes)
- fmt.Println("str -- ", str, " newStr --", newStr)
-
- //因go为utf8编码,byte对应一个字节,汉字为三个字节,无法放入单个字节
- //rune的定义:32位有符号整形,int32的别名;将string转换成rune数组时
- //解决了汉字长度的问题
- // bytes[0] = '我'
- //rune 按照字符处理string
- strRune := []rune(str)
- strRune[0] = '我'
- newStr = string(strRune)
- fmt.Println(newStr)
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。