【golang】3.0 指针、数组、range关键字、Slice(切片)

指针

指针在go语言中是一个很重要的概念,但比c语言简单多了。

指针简单在:指针不能运算
参数传递:值传递还是引用传递。go语言只有值传递。

值传递验证:

package main

import "fmt"

func swap(a, b int) {
    a, b = b, a
}

func main() {
    a, b := 3, 4
    swap(a, b)
    fmt.Println(a, b)
}

image.png

指针传递:

package main

import "fmt"

func swap(a, b int) {
    a, b = b, a
}
func swapPrint(a, b *int) {
    *a, *b = *b, *a
}

func main() {
    a, b := 3, 4
    //swap(a, b)
    swapPrint(&a, &b)
    fmt.Println(a, b)
}
image.png

数组

数据的定义需要声明数组长度。

package main

import "fmt"

func main() {

    var arr1 [5]int
    arr2 := [3]int{1, 3, 5}
    arr3 := [...]int{2, 4, 6, 8, 10}

    fmt.Println(arr1, arr2, arr3)
}
image.png

二维数组

package main

import "fmt"

func main() {

    var arr1 [5]int
    arr2 := [3]int{1, 3, 5}
    arr3 := [...]int{2, 4, 6, 8, 10}

    fmt.Println(arr1, arr2, arr3)

    //二维数组
    var grid [4][5]int
    var grid2 [4][5]bool
    fmt.Println(grid)
    fmt.Println(grid2)
}

image.png

range关键字使用

package main

import "fmt"

func main() {

    var arr1 [5]int
    arr2 := [3]int{1, 3, 5}
    arr3 := [...]int{2, 4, 6, 8, 10}

    fmt.Println(arr1, arr2, arr3)

    //二维数组
    var grid [4][5]int
    var grid2 [4][5]bool
    fmt.Println(grid)
    fmt.Println(grid2)

    //数组遍历
    //for i := 0; i < len(arr3); i++ {
    //如上可以写成如下,效果相等,i为下标,v为值
    for i, v := range arr3 {
        fmt.Println(arr3[i], v)
    }
    fmt.Println("*******************")
    // 如下验证值传递还是引用传递
    for i, v := range arr3 {
        v++
        fmt.Println(arr3[i], v)
    }

    // 如果只想用值
    for _, v := range arr3 {
        fmt.Println(v)
    }

}
image.png

为什么要用range:


image.png

数组是值类型,可以更好的验证:

package main

import "fmt"

func arrayDemo() {

    var arr1 [5]int
    arr2 := [3]int{1, 3, 5}
    arr3 := [...]int{2, 4, 6, 8, 10}

    fmt.Println(arr1, arr2, arr3)

    //二维数组
    var grid [4][5]int
    var grid2 [4][5]bool
    fmt.Println(grid)
    fmt.Println(grid2)

    //数组遍历
    //for i := 0; i < len(arr3); i++ {
    //如上可以写成如下,效果相等,i为下标,v为值
    for i, v := range arr3 {
        fmt.Println(arr3[i], v)
    }
    fmt.Println("*******************")
    // 如下验证值传递还是引用传递
    for i, v := range arr3 {
        v++
        fmt.Println(arr3[i], v)
    }

    // 如果只想用值
    for _, v := range arr3 {
        fmt.Println(v)
    }
}

func printArray(arr [5]int) {
    arr[0] = 100
    for i, v := range arr {
        fmt.Println(arr[i], v)
    }

}

func main() {
    arr3 := [...]int{2, 4, 6, 8, 10}
    printArray(arr3)
    fmt.Println("***********")
    fmt.Println(arr3)
}
image.png

如果用指针,可以达到一个引用传递的效果。

......
func printArrayPointer(arr *[5]int) {
    arr[0] = 100
    for i, v := range arr {
        fmt.Println(arr[i], v)
    }

}

func main() {
    arr3 := [...]int{2, 4, 6, 8, 10}
    //printArray(arr3)
    //fmt.Println("***********")
    //fmt.Println(arr3)
    printArrayPointer(&arr3)
    fmt.Println(arr3)
}
image.png

这里可以看出,数组用起来很麻烦,需要指定数组的长度,更多的使用Slice(切片)

Slice(切片)

切片的使用:

package main

import "fmt"

func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    // 计算机的区间一般为半开半闭区间,及2,3,4,5
    s := arr[2:6]
    fmt.Println(arr, s)
}
image.png

为了更好的理解切片,用例如下:

package main

import "fmt"

func main() {
    arr := [...]int{4, 0, 1, 2, 3, 4, 5, 6, 7}
    // 计算机的区间一般为半开半闭区间,及2,3,4,5
    //s := arr[2:6]
    fmt.Println("arr[2:6] = ", arr[2:6])
    fmt.Println("arr[:6] = ", arr[:6])
    fmt.Println("arr[2:] = ", arr[2:])
    fmt.Println("arr[:] = ", arr[:])
}
image.png

arr[2:6],相当于对arr的一个视图

package main

import "fmt"

func updateSlice(s []int) {
    s[0] = 100
}

func main() {
    arr := [...]int{4, 0, 1, 2, 3, 4, 5, 6, 7}
    // 计算机的区间一般为半开半闭区间,及2,3,4,5
    //s := arr[2:6]
    //arr[2:6],相当于对arr的一个视图
    fmt.Println("arr[2:6] = ", arr[2:6])
    fmt.Println("arr[:6] = ", arr[:6])
    s1 := arr[2:]
    fmt.Println("arr[2:](s1) = ", s1)
    s2 := arr[:]
    fmt.Println("arr[:](s2) = ", s2)

    fmt.Println("After updateSlice(s1)")
    updateSlice(s1)
    fmt.Println(s1)
    fmt.Println(arr)

    fmt.Println("After updateSlice(s2)")
    updateSlice(s2)
    fmt.Println(s2)
    fmt.Println(arr)

}
image.png

视图是告诉计算机,这是一个底层数据的视图,如果改掉将等同于整个数据的改动。

也就是说,我们需要用指针达成的效果,可以如下进行:

package main

import "fmt"

func arrayDemo() {

    var arr1 [5]int
    arr2 := [3]int{1, 3, 5}
    arr3 := [...]int{2, 4, 6, 8, 10}

    fmt.Println(arr1, arr2, arr3)

    //二维数组
    var grid [4][5]int
    var grid2 [4][5]bool
    fmt.Println(grid)
    fmt.Println(grid2)

    //数组遍历
    //for i := 0; i < len(arr3); i++ {
    //如上可以写成如下,效果相等,i为下标,v为值
    for i, v := range arr3 {
        fmt.Println(arr3[i], v)
    }
    fmt.Println("*******************")
    // 如下验证值传递还是引用传递
    for i, v := range arr3 {
        v++
        fmt.Println(arr3[i], v)
    }

    // 如果只想用值
    for _, v := range arr3 {
        fmt.Println(v)
    }
}

func printArray(arr [5]int) {
    arr[0] = 100
    for i, v := range arr {
        fmt.Println(arr[i], v)
    }

}
func printArrayPointer(arr *[5]int) {
    arr[0] = 100
    for i, v := range arr {
        fmt.Println(arr[i], v)
    }

}

func printArraySlice(arr []int) {
    arr[0] = 100
    for i, v := range arr {
        fmt.Println(arr[i], v)
    }
}

func main() {
    var arr1 [5]int
    arr3 := [...]int{2, 4, 6, 8, 10}
    //printArray(arr3)
    //fmt.Println("***********")
    //fmt.Println(arr3)
    //printArrayPointer(&arr3)
    //fmt.Println(arr3)

    printArraySlice(arr1[:])
    fmt.Println(arr1)
    printArraySlice(arr3[:])
    fmt.Println(arr3)
}

slice还可以继续切片。

package main

import "fmt"

func updateSlice(s []int) {
    s[0] = 100
}

func main() {
    arr := [...]int{4, 0, 1, 2, 3, 4, 5, 6, 7}
    // 计算机的区间一般为半开半闭区间,及2,3,4,5
    //s := arr[2:6]
    //arr[2:6],相当于对arr的一个视图
    fmt.Println("arr[2:6] = ", arr[2:6])
    fmt.Println("arr[:6] = ", arr[:6])
    s1 := arr[2:]
    fmt.Println("arr[2:](s1) = ", s1)
    s2 := arr[:]
    fmt.Println("arr[:](s2) = ", s2)

    fmt.Println("After updateSlice(s1)")
    updateSlice(s1)
    fmt.Println(s1)
    fmt.Println(arr)

    fmt.Println("After updateSlice(s2)")
    updateSlice(s2)
    fmt.Println(s2)
    fmt.Println(arr)

    // slice还可以进一步slice
    fmt.Println("Re slice")
    fmt.Println(s2)
    s2 = s2[:5]
    fmt.Println(s2)
    s2 = s2[2:]
    fmt.Println(s2)
}
image.png

切片的复杂用法

package main

import "fmt"

func updateSlice(s []int) {
    s[0] = 100
}

func sliceDemo(arr []int) {
    // 计算机的区间一般为半开半闭区间,及2,3,4,5
    //s := arr[2:6]
    //arr[2:6],相当于对arr的一个视图
    fmt.Println("arr[2:6] = ", arr[2:6])
    fmt.Println("arr[:6] = ", arr[:6])
    s1 := arr[2:]
    fmt.Println("arr[2:](s1) = ", s1)
    s2 := arr[:]
    fmt.Println("arr[:](s2) = ", s2)

    fmt.Println("After updateSlice(s1)")
    updateSlice(s1)
    fmt.Println(s1)
    fmt.Println(arr)

    fmt.Println("After updateSlice(s2)")
    updateSlice(s2)
    fmt.Println(s2)
    fmt.Println(arr)

    // slice还可以进一步slice
    fmt.Println("Re slice")
    fmt.Println(s2)
    s2 = s2[:5]
    fmt.Println(s2)
    s2 = s2[2:]
    fmt.Println(s2)

}

func main() {
    arr := [...]int{4, 0, 1, 2, 3, 4, 5, 6, 7}
    //sliceDemo(arr[:])

    s1 := arr[2:6]
    fmt.Println(s1)
    s2 := s1[3:5]
    fmt.Println(s2)
}

如上代码,是不报错的:


image.png

涉及到视图的原理:


image.png

image.png

image.png

所以可以如下打印:

......
func main() {
    arr := [...]int{4, 0, 1, 2, 3, 4, 5, 6, 7}
    //sliceDemo(arr[:])
    fmt.Println("arr=", arr)
    s1 := arr[2:6]
    s2 := s1[3:5]
    fmt.Printf("s1=%v,len(s1)=%d,cap(s1)=%d\n", s1, len(s1), cap(s1))
    fmt.Printf("s2=%v,len(s2)=%d,cap(s2)=%d\n", s2, len(s2), cap(s2))
}
image.png

切片扩展元素

package main

import "fmt"

func updateSlice(s []int) {
    s[0] = 100
}

func sliceDemo(arr []int) {
    // 计算机的区间一般为半开半闭区间,及2,3,4,5
    //s := arr[2:6]
    //arr[2:6],相当于对arr的一个视图
    fmt.Println("arr[2:6] = ", arr[2:6])
    fmt.Println("arr[:6] = ", arr[:6])
    s1 := arr[2:]
    fmt.Println("arr[2:](s1) = ", s1)
    s2 := arr[:]
    fmt.Println("arr[:](s2) = ", s2)

    fmt.Println("After updateSlice(s1)")
    updateSlice(s1)
    fmt.Println(s1)
    fmt.Println(arr)

    fmt.Println("After updateSlice(s2)")
    updateSlice(s2)
    fmt.Println(s2)
    fmt.Println(arr)

    // slice还可以进一步slice
    fmt.Println("Re slice")
    fmt.Println(s2)
    s2 = s2[:5]
    fmt.Println(s2)
    s2 = s2[2:]
    fmt.Println(s2)

}

func main() {
    arr := [...]int{4, 0, 1, 2, 3, 4, 5, 6, 7}
    //sliceDemo(arr[:])
    fmt.Println("arr=", arr)
    s1 := arr[2:6]
    s2 := s1[3:5]
    fmt.Printf("s1=%v,len(s1)=%d,cap(s1)=%d\n", s1, len(s1), cap(s1))
    fmt.Printf("s2=%v,len(s2)=%d,cap(s2)=%d\n", s2, len(s2), cap(s2))

    s3 := append(s2, 10)
    fmt.Println("s3=", s3)
    s4 := append(s3, 11)
    fmt.Println("s4=", s4)
    s5 := append(s4, 12)
    fmt.Println("s3,s4,s5=", s3, s4, s5)
    fmt.Println("arr=", arr)
}
image.png

这里发现arr的11和12不见了。


image.png

更深入测试

package main

import "fmt"

func printSlice(s []int) {
    fmt.Printf("len=%d,cap=%d\n", len(s), cap(s))
}

func main() {
    var s []int

    for i := 0; i < 100; i++ {
        printSlice(s)
        s = append(s, 2*i+1)
    }
    fmt.Println(s)
}

运行结果如下:

len=0,cap=0
len=1,cap=1
len=2,cap=2
len=3,cap=4
len=4,cap=4
len=5,cap=8
len=6,cap=8
len=7,cap=8
len=8,cap=8
len=9,cap=16
len=10,cap=16
len=11,cap=16
len=12,cap=16
len=13,cap=16
len=14,cap=16
len=15,cap=16
len=16,cap=16
len=17,cap=32
len=18,cap=32
len=19,cap=32
len=20,cap=32
len=21,cap=32
len=22,cap=32
len=23,cap=32
len=24,cap=32
len=25,cap=32
len=26,cap=32
len=27,cap=32
len=28,cap=32
len=29,cap=32
len=30,cap=32
len=31,cap=32
len=32,cap=32
len=33,cap=64
len=34,cap=64
len=35,cap=64
len=36,cap=64
len=37,cap=64
len=38,cap=64
len=39,cap=64
len=40,cap=64
len=41,cap=64
len=42,cap=64
len=43,cap=64
len=44,cap=64
len=45,cap=64
len=46,cap=64
len=47,cap=64
len=48,cap=64
len=49,cap=64
len=50,cap=64
len=51,cap=64
len=52,cap=64
len=53,cap=64
len=54,cap=64
len=55,cap=64
len=56,cap=64
len=57,cap=64
len=58,cap=64
len=59,cap=64
len=60,cap=64
len=61,cap=64
len=62,cap=64
len=63,cap=64
len=64,cap=64
len=65,cap=128
len=66,cap=128
len=67,cap=128
len=68,cap=128
len=69,cap=128
len=70,cap=128
len=71,cap=128
len=72,cap=128
len=73,cap=128
len=74,cap=128
len=75,cap=128
len=76,cap=128
len=77,cap=128
len=78,cap=128
len=79,cap=128
len=80,cap=128
len=81,cap=128
len=82,cap=128
len=83,cap=128
len=84,cap=128
len=85,cap=128
len=86,cap=128
len=87,cap=128
len=88,cap=128
len=89,cap=128
len=90,cap=128
len=91,cap=128
len=92,cap=128
len=93,cap=128
len=94,cap=128
len=95,cap=128
len=96,cap=128
len=97,cap=128
len=98,cap=128
len=99,cap=128
[1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 
                                                                                57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99 101 103 105 10
                                                                               07 109 111 113 115 117 119 121 123 125 127 129 131 133 135 137 139 141 143 145 14
                                                                               47 149 151 153 155 157 159 161 163 165 167 169 171 173 175 177 179 181 183 185 18
                                                                               87 189 191 193 195 197 199]

Process finished with the exit code 0

如果声明一个切片,但不初始化数据。

package main

import "fmt"

func printSlice(s []int) {
    fmt.Printf("%v,len=%d,cap=%d\n", s, len(s), cap(s))
}

func main() {
    //var s []int

    //for i := 0; i < 100; i++ {
    //  printSlice(s)
    //  s = append(s, 2*i+1)
    //}
    //fmt.Println(s)

    // 如果需要指定一个可变数组,但不知道值,go叫切片,可以如下声明
    s2 := make([]int, 16)
    // 要求初始化10个数据要存储,但数组长度为32
    s3 := make([]int, 10, 32)
    printSlice(s2)
    printSlice(s3)
}
image.png

Slice(切片)拷贝

package main

import "fmt"

func printSlice(s []int) {
    fmt.Printf("%v,len=%d,cap=%d\n", s, len(s), cap(s))
}

func main() {
    //var s []int

    //for i := 0; i < 100; i++ {
    //  printSlice(s)
    //  s = append(s, 2*i+1)
    //}
    //fmt.Println(s)
    fmt.Println("Created Slice")
    s1 := []int{2, 4, 6, 8}
    // 如果需要指定一个可变数组,但不知道值,go叫切片,可以如下声明
    s2 := make([]int, 16)
    // 要求初始化10个数据要存储,但数组长度为32
    s3 := make([]int, 10, 32)
    printSlice(s2)
    printSlice(s3)

    fmt.Println("Copying slice")
    copy(s2, s1)
    printSlice(s2)

    fmt.Println()
}
image.png

常用的:删除头和尾

package main

import "fmt"

func printSlice(s []int) {
    fmt.Printf("%v,len=%d,cap=%d\n", s, len(s), cap(s))
}

func main() {
    //var s []int

    //for i := 0; i < 100; i++ {
    //  printSlice(s)
    //  s = append(s, 2*i+1)
    //}
    //fmt.Println(s)
    fmt.Println("Created Slice")
    s1 := []int{2, 4, 6, 8}
    // 如果需要指定一个可变数组,但不知道值,go叫切片,可以如下声明
    s2 := make([]int, 16)
    // 要求初始化10个数据要存储,但数组长度为32
    s3 := make([]int, 10, 32)
    printSlice(s2)
    printSlice(s3)

    fmt.Println("Copying slice")
    copy(s2, s1)
    printSlice(s2)

    //删除任意位置
    fmt.Println("Deleting elements from slice")
    s2 = append(s2[:3], s2[4:]...)
    printSlice(s2)

    //删除头
    fmt.Println("Popping from front")
    front := s2[0]
    s2 = s2[1:]
    fmt.Println(front)
    printSlice(s2)
    //删除尾
    fmt.Println("Popping from back")
    tail := s2[len(s2)-1]
    s2 = s2[:len(s2)-1]
    fmt.Println(tail)
    printSlice(s2)

}
image.png

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):