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

数组

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

package main

import(
    "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,5}
    fmt.Println(arr2)

    var arr3 = [...]int{1,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]
10
0
0
0
0
0 10
1 0
2 0
3 0
4 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 main

import(
    "fmt"

)


func main() {
    var slice []int
    var arr [5]int = [5]int{1,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,4}
    fmt.Println(slice3)

}

输出如下:

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

切片内存如何变化的?

package main

import(
    "fmt"

)

func main() {
    var a [5]int = [...]int{1,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[1] = 1000
    fmt.Println("after a:",a)
    fmt.Println(s) 
    //容量改变,重新分配内存 
    fmt.Printf("%p %p\n",&a[1])

}

输出如下:

0xc04204c1e8 0xc04204c1e8
before 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 0xc04204c1e8
PS 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 main

import(
    "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 main

import(
    "fmt"

)

/*切片会被修改*/
func modify(b []int){
    b[1] = 200
}

func modify1(b *[]int){
    (*b)[1] = 2000
}

func main() {

    var b []int = []int{1,3}
    fmt.Println(b)
    //修改切片方法1--直接穿切片
    modify(b)
    fmt.Println(b)
    //修改切片方法2--传地址值
    modify1(&b)
    fmt.Println(b)

    //数组不会被修改,参数为数组
    var d [3]int = [...]int{3,5}
    modify3(d)
    fmt.Println(d)

/*演示切片的内存布局*/
    testSlice5()
}

func modify3(b [3]int){
    b[1] = 200
}
/*演示切片的内存布局*/
func testSlice5(){
    fmt.Println("----------------")

    var a = [10]int{1,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]
----------------
0xc0420101e8
0xc0420101e8
[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 main

import(
    "fmt"

)

func main() {
    var a []int= []int{1,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,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 main

import(
    "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) }

输出如下:

hel
llogo
我ahellogo
oello world
PS E:\golang\go_pro\src\safly>

切片循环

package main

import(
    "fmt"

)

func main() {
    var a []int= []int{1,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 1
1 2
2 3
3 4
4 5
5 6
1
2
3
4
5
6
PS E:\golang\go_pro\src\safly>

相关文章

程序目录结构 简单实现,用户登录后返回一个jwt的token,下次请求带上token请求用户信息接口并返回信息...
本篇博客的主要内容是用go写一个简单的Proof-of-Work共识机制,不涉及到网络通信环节,只是一个本地的简...
简介 默克尔树(MerkleTree)是一种典型的二叉树结构,其主要特点为: 最下面的叶节点包含存储数据或其...
接下来学习并发编程, 并发编程是go语言最有特色的地方, go对并发编程是原生支持. goroutine是go中最近本...
先普及一下, 什么是广度优先搜索 广度优先搜索类似于树的层次遍历。从图中的某一顶点出发,遍历每一个顶...
第一天: 接口的定义和实现 第二天: 一. go语言是面向接口编程. 在学习继承的时候说过, go语言只有封装,...