golang基础-数组、切片创建_内存_底层实现_修改值_拷贝_循环、string与切片

来源:互联网 发布:淘宝禁止开店 编辑:程序博客网 时间:2024/06/05 05:17

数组

数组:是同一种数据类型的固定长度的序列
数组定义:var a [len]int,比如:var a[5]int,一旦定义,长度不能变
长度是数组类型的一部分,因此,var a[5] int和var a[10]int是不同的类型
数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1
访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic
数组是值类型,因此改变副本的值,不会改变本身的值

package mainimport(    "fmt")func main() {    //为数组索引赋值    var a [5]int    a[0] = 10    fmt.Println(a)    //遍历数组2种方法    for i:=0;i<len(a);i++{        fmt.Println(a[i])    }    for i,v := range a{        fmt.Println(i,v)    }    //值传递    test()    var aa [5]int     //通过方法参数值传递    test1(aa)    fmt.Println(aa)    //传递地址值    test2(&aa)    fmt.Println(aa)    //数组初始化5种方式    var arr1 [5]int = [5]int{1,2,3,4,5}    fmt.Println(arr1)    var arr2 = [5]int{1,2,3,4,5}    fmt.Println(arr2)    var arr3 = [...]int{1,2,4,5,6}    fmt.Println(arr3)    var arr4 = [...]int{1:1,2:2}    fmt.Println(arr4)    var arr5 = [5]int{1:2,3:4}    fmt.Println(arr5)}func test(){    var a [5]int    b := a    b[0] = 100    fmt.Println(a)}func test1(arr [5]int){    arr[0] = 100}func test2(arr *[5]int){    (*arr)[0] = 100}

输出如下:

[10 0 0 0 0]1000000 101 02 03 04 0[0 0 0 0 0][0 0 0 0 0][100 0 0 0 0][1 2 3 4 5][1 2 3 4 5][1 2 4 5 6][0 1 2][0 2 0 4 0]

切片

切片:切片是数组的一个引用,因此切片是引用类型
切片的长度可以改变,因此,切片是一个可变的数组

切片遍历方式和数组一样,可以用len()求长度
cap可以求出slice最大的容量,0 <= len(slice) <= (array),其中array是slice引用的数组
切片的定义:var 变量名 []类型,比如 var str []string var arr []int

package mainimport(    "fmt")func main() {    var slice []int    var arr [5]int = [5]int{1,2,3,4,5}    slice = arr[2:5]    fmt.Println(slice)    //长度    fmt.Println(len(slice))    //最大容量    fmt.Println(cap(slice))    slice = slice[0:1]    fmt.Println(len(slice))    fmt.Println(cap(slice))    //切片的其他声明方法    var slice1 []int = arr[:]    fmt.Println(slice1)    var slice2 []int = arr[0:3]    fmt.Println(slice2)    var slice3 []int = []int{1,2,4}    fmt.Println(slice3)}

输出如下:

2017/10/24 13:46:43 debugger.go:499: continuing[3 4 5]3313[1 2 3 4 5][1 2 3][1 2 4]

切片内存如何变化的?

package mainimport(    "fmt")func main() {    var a [5]int = [...]int{1,2,3,4,5}    //切片    s:= a[1:]    s[1] = 100    //内存地址一样,修改了s的索引值,也就修改了a的索引值    fmt.Printf("%p %p\n",s,&a[1])    fmt.Println("before a:",a)    fmt.Println(s)    s = append(s,10)    s = append(s,10)    s = append(s,10)    s = append(s,10)    s = append(s,10)    s[1] = 1000    fmt.Println("after a:",a)    fmt.Println(s)     //容量改变,重新分配内存                                     fmt.Printf("%p %p\n",s,&a[1])}

输出如下:

0xc04204c1e8 0xc04204c1e8before a: [1 2 100 4 5][2 100 4 5]after a: [1 2 100 4 5][2 1000 4 5 10 10 10 10 10]0xc042014200 0xc04204c1e8PS E:\golang\go_pro\src\safly>

简单解释下:
这里写图片描述

创建一个数组a,初始值为{1,2,3,4,5},然后构造一个从索引1开始的数组切片,{2,3,4,5},这里的切片、数组都是同一块内存地址,然后将s[1]赋值为100,由于内存地址是一样的,所以a为{1,2,100,4,5}
s为[2,100,4,5]
接下来为s切片扩充容量,然后修改了s[1] = 1000,最后s为2 1000 4 5 10 10 10 10 10,a依然是[1 2 100 4 5]
,由于底层算法,扩容后,内存地址a和s的就不同了,s从新创建了一个内存地址0xc042014200

切片的底层代码实现

package mainimport(    "fmt")/*切片底层形式*/type slice struct{    ptr *[5]int    len int     cap int}/*构造一个slice*/func makeSlice(s slice,cap int) slice{    s.ptr = new([5]int)    s.cap = cap    s.len = 0    return s}func testSlice(){    //slice类型    var a slice     a = makeSlice(a,5)    a.ptr[0] = 100    fmt.Println(a.ptr)}func main() {    testSlice()}

输出如下:

&[100 0 0 0 0]

修改切片值、演示切片内存地址

package mainimport(    "fmt")/*切片会被修改*/func modify(b []int){    b[1] = 200}func modify1(b *[]int){    (*b)[1] = 2000}func main() {    var b []int = []int{1,2,3}    fmt.Println(b)    //修改切片方法1--直接穿切片    modify(b)    fmt.Println(b)    //修改切片方法2--传地址值    modify1(&b)    fmt.Println(b)    //数组不会被修改,参数为数组    var d [3]int = [...]int{3,4,5}    modify3(d)    fmt.Println(d)/*演示切片的内存布局*/    testSlice5()}func modify3(b [3]int){    b[1] = 200}/*演示切片的内存布局*/func testSlice5(){    fmt.Println("----------------")    var a = [10]int{1,2,3,4}    b :=a[1:5]    fmt.Printf("%p\n",b)    fmt.Printf("%p\n",&a[1])    fmt.Println(a,b)}

输出如下:

[1 2 3][1 200 3][1 2000 3][3 4 5]----------------0xc0420101e80xc0420101e8[1 2 3 4 0 0 0 0 0 0] [2 3 4 0]PS E:\golang\go_pro\src\safly>

切片拷贝make\copy\append

package mainimport(    "fmt")func main() {    var a []int= []int{1,2,3,4,5,6}    fmt.Println(a)    b:= make([]int,1)    fmt.Println(b)    //将a的值拷贝到b    copy(b,a)    fmt.Println(b)    //将a拷贝到c    c:=make([]int,10)    copy(c,a)    fmt.Println(c)    //append自己    d :=append(c,c...)    fmt.Println(d)    //append元素    e:=append(c,2,4)    fmt.Println(e)}

输出如下:

PS E:\golang\go_pro\src\safly> go run demo.go[1 2 3 4 5 6][0][1][1 2 3 4 5 6 0 0 0 0][1 2 3 4 5 6 0 0 0 0 1 2 3 4 5 6 0 0 0 0][1 2 3 4 5 6 0 0 0 0 2 4]PS E:\golang\go_pro\src\safly>

string与slice

string底层就是一个byte的数组,因此,也可以进行切片操作

这里写图片描述

string本身是不可变的,因此要改变string中字符,需要如下操作

package mainimport(    "fmt")func main() {    s:="hellogo"    s1:=s[0:3]    s2:=s[2:]    fmt.Println(s1)    fmt.Println(s2)    testModifyStr()}func testModifyStr(){       //带中文的    s:="我的hellogo"    s1:=[]rune(s)    s1[1] = 'a'    str:=string(s1)    fmt.Println(str)    aaa := "hello world"    bbb := []byte(aaa)    bbb[0] = 'o'    str = string(bbb)    fmt.Println(str)}

输出如下:

helllogo我ahellogooello worldPS E:\golang\go_pro\src\safly>

切片循环

package mainimport(    "fmt")func main() {    var a []int= []int{1,2,3,4,5,6}    fmt.Println(a)    for index, val := range a {        fmt.Println(index,val)    }    for _, val := range a {        fmt.Print`n(val)    }}

输出如下:

PS E:\golang\go_pro\src\safly> go run demo.go[1 2 3 4 5 6]0 11 22 33 44 55 6123456PS E:\golang\go_pro\src\safly>
原创粉丝点击