Golang 【第七篇】数组和切片

Golang 【第七篇】数组和切片

 

1 数组的内存布局

 

 

2 数组的使用

package main
import (
    "fmt"
)

func main() {

    var intArr [3]int //int占8个字节
    //当我们定义完数组后,其实数组的各个元素有默认值 0
    fmt.Println(intArr)
    intArr[0] = 10
    intArr[1] = 20
    intArr[2] = 30
    fmt.Println(intArr)
    fmt.Printf("intArr的地址=%p intArr[0] 地址%p intArr[1] 地址%p intArr[2] 地址%p\n", 
        &intArr, &intArr[0], &intArr[1], &intArr[2])


    //从终端循环输入5个成绩,保存到float64数组,并输出.
    // var score [5]float64

    // for i := 0; i < len(score); i++ {
    //     fmt.Printf("请输入第%d个元素的值\n", i+1)
    //     fmt.Scanln(&score[i])
    // }
    
    // //变量数组打印
    // for i := 0; i < len(score); i++ {
    //     fmt.Printf("score[%d]=%v\n", i, score[i])
    // }

    //四种初始化数组的方式
    var numArr01 [3]int = [3]int{1, 2, 3}
    fmt.Println("numArr01=", numArr01)

    var numArr02 = [3]int{5, 6, 7}
    fmt.Println("numArr02=", numArr02)
    //这里的 [...] 是规定的写法
    var numArr03 = [...]int{8, 9, 10}
    fmt.Println("numArr03=", numArr03)

    var numArr04 = [...]int{1: 800, 0: 900, 2:999}
    fmt.Println("numArr04=", numArr04)

    //类型推导
    strArr05 := [...]string{1: "tom", 0: "jack", 2:"mary"}
    fmt.Println("strArr05=", strArr05)
}
数组的使用
package main
import (
    "fmt"
)

//函数
func test01(arr [3]int) {
    arr[0] = 88
} 

//函数
func test02(arr *[3]int) {
    fmt.Printf("arr指针的地址=%p", &arr)
    (*arr)[0] = 88 //!!
} 

func main() {
    
    /*
    //数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的, 不能动态变化。
    var arr01 [3]int
    arr01[0] = 1
    arr01[1] = 30
    //这里会报错
    arr01[2] = 1.1  
    //其长度是固定的, 不能动态变化,否则报越界
    arr01[3] = 890

    fmt.Println(arr01)
    */

    //数组创建后,如果没有赋值,有默认值(零值)
    //1. 数值(整数系列, 浮点数系列) =>0
    //2. 字符串 ==> ""
    //3. 布尔类型 ==> false

    var arr01 [3]float32
    var arr02 [3]string
    var arr03 [3]bool
    fmt.Printf("arr01=%v arr02=%v arr03=%v\n", arr01, arr02, arr03)

    //数组的下标是从0开始的

    // var arr04 [3]string // 0 - 2
    // var index int = 3
    // arr04[index] = "tom" // 因为下标是 0 - 2 ,因此arr04[3]就越界

    //Go的数组属值类型, 在默认情况下是值传递, 因此会进行值拷贝。数组间不会相互影响

    // arr := [3]int{11, 22, 33}
    // test01(arr)
    // fmt.Println("main arr=", arr) //


    arr := [3]int{11, 22, 33}
    fmt.Printf("arr 的地址=%p", &arr)
    test02(&arr)
    fmt.Println("main arr=", arr)
}
arraydetails

 

3 数组的遍历

package main
import (
    "fmt"
)

func main() {

    //演示for-range遍历数组
     heroes  := [...]string{"宋江", "吴用", "卢俊义"}
    //使用常规的方式遍历,我不写了..

    for i, v := range heroes {
        fmt.Printf("i=%v v=%v\n", i , v)
        fmt.Printf("heroes[%d]=%v\n", i, heroes[i])
    }

    for _, v := range heroes {
        fmt.Printf("元素的值=%v\n", v)
    }
}
数组的遍历

 

4 exercise

package main 
import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    //1)创建一个byte类型的26个元素的数组,分别 放置'A'-'Z‘。
    //使用for循环访问所有元素并打印出来。提示:字符数据运算 'A'+1 -> 'B'

    //思路
    //1. 声明一个数组 var myChars [26]byte
    //2. 使用for循环,利用 字符可以进行运算的特点来赋值 'A'+1 -> 'B'
    //3. 使用for打印即可
    //代码:
    var myChars [26]byte
    for i := 0; i < 26; i++ {
        myChars[i] = 'A' + byte(i) // 注意需要将 i => byte
    }

    for i := 0; i < 26; i++ {
        fmt.Printf("%c ", myChars[i])
    }

    //请求出一个数组的最大值,并得到对应的下标

    //思路
    //1. 声明一个数组 var intArr[5] = [...]int {1, -1, 9, 90, 11}
    //2. 假定第一个元素就是最大值,下标就0
    //3. 然后从第二个元素开始循环比较,如果发现有更大,则交换

    fmt.Println()
    var intArr [6]int = [...]int {1, -1, 9, 90, 11, 9000}
    maxVal := intArr[0]
    maxValIndex := 0

    for i := 1; i < len(intArr); i++ {
        //然后从第二个元素开始循环比较,如果发现有更大,则交换
        if maxVal < intArr[i] {
            maxVal = intArr[i]
            maxValIndex = i
        }
    }
    fmt.Printf("maxVal=%v maxValIndex=%v\n\n", maxVal, maxValIndex)

    //请求出一个数组的和和平均值。for-range
    //思路
    //1. 就是声明一个数组  var intArr[5] = [...]int {1, -1, 9, 90, 11}
    //2. 求出和sum
    //3. 求出平均值
    //代码
    var intArr2 [5]int = [...]int {1, -1, 9, 90, 12}
    sum := 0
    for _, val := range intArr2 {
        //累计求和
        sum += val
    }

    //如何让平均值保留到小数.
    fmt.Printf("sum=%v 平均值=%v \n\n", sum, float64(sum) / float64(len(intArr2)))


    //要求:随机生成五个数,并将其反转打印
    //思路
    //1. 随机生成五个数 , rand.Intn() 函数
    //2. 当我们得到随机数后,就放到一个数组 int数组
    //3. 反转打印 , 交换的次数是  len / 2, 倒数第一个和第一个元素交换, 倒数第2个和第2个元素交换

    var intArr3 [5]int 
    //为了每次生成的随机数不一样,我们需要给一个seed值
    len := len(intArr3)
    
    rand.Seed(time.Now().UnixNano())
    for i := 0; i < len; i++ {
        intArr3[i] = rand.Intn(100) //  0<=n<100
    }

    fmt.Println("交换前~=", intArr3)
    //反转打印 , 交换的次数是  len / 2, 
    //倒数第一个和第一个元素交换, 倒数第2个和第2个元素交换
    temp := 0  //做一个临时变量
    for i := 0; i < len / 2; i++ {
        temp = intArr3[len - 1 - i]  
        intArr3[len - 1 - i] = intArr3[i]
        intArr3[i] = temp
    }

    fmt.Println("交换后~=", intArr3)
}
arrayExercise

 

5 切片

 

 5.1切片的内存布局

 

 5.2 切片的使用

package main
import (
    "fmt"
)

func main() {

    //演示切片的基本使用
    var intArr [5]int = [...]int{1, 22, 33, 66, 99}
    //声明/定义一个切片
    //slice := intArr[1:3]
    //1. slice 就是切片名
    //2. intArr[1:3] 表示 slice 引用到intArr这个数组 
    //3. 引用intArr数组的起始下标为 1 , 最后的下标为3(但是不包含3)    
    slice := intArr[1:3] 
    fmt.Println("intArr=", intArr)
    fmt.Println("slice 的元素是 =", slice) //  22, 33
    fmt.Println("slice 的元素个数 =", len(slice)) // 2
    fmt.Println("slice 的容量 =", cap(slice)) // 切片的容量是可以动态变化  

    fmt.Printf("intArr[1]的地址=%p\n", &intArr[1])
    fmt.Printf("slice[0]的地址=%p slice[0==%v\n", &slice[0], slice[0])
    slice[1] = 34
    fmt.Println()
    fmt.Println()
    fmt.Println("intArr=", intArr)
    fmt.Println("slice 的元素是 =", slice) //  22, 33

}
1 切片的基本使用
package main
import (
    "fmt"
)

func main() {

    //演示切片的使用 make
    var slice []float64 = make([]float64, 5, 10)
    slice[1] = 10
    slice[3] = 20
    //对于切片,必须make使用.
    fmt.Println(slice)
    fmt.Println("slice的size=", len(slice))
    fmt.Println("slice的cap=", cap(slice))


    //方式3
    fmt.Println()
    //第3种方式:定义一个切片,直接就指定具体数组,使用原理类似make的方式
    var strSlice []string = []string{"tom", "jack", "mary"}
    fmt.Println("strSlice=", strSlice)
    fmt.Println("strSlice size=", len(strSlice)) //3
    fmt.Println("strSlice cap=", cap(strSlice)) // ?

}
make 创建切片

 

package main
import (
    "fmt"
)

func main() {

    //使用常规的for循环遍历切片
    var arr [5]int = [...]int{10, 20, 30, 40, 50}
    //slice := arr[1:4] // 20, 30, 40
    slice := arr[1:4]
    for i := 0; i < len(slice); i++ {
        fmt.Printf("slice[%v]=%v ", i, slice[i])
    }

    fmt.Println()
    //使用for--range 方式遍历切片
    for i, v := range slice {
        fmt.Printf("i=%v v=%v \n", i, v)
    }

    slice2 := slice[1:2] //  slice [ 20, 30, 40]    [30]
    slice2[0] = 100  // 因为arr , slice 和slice2 指向的数据空间是同一个,因此slice2[0]=100,其它的都变化

    fmt.Println("slice2=", slice2)
    fmt.Println("slice=", slice)
    fmt.Println("arr=", arr)

    fmt.Println()

    //用append内置函数,可以对切片进行动态追加
    var slice3 []int = []int{100, 200, 300}
    //通过append直接给slice3追加具体的元素
    slice3 = append(slice3, 400, 500, 600)
    fmt.Println("slice3", slice3) //100, 200, 300,400, 500, 600

    //通过append将切片slice3追加给slice3
    slice3 = append(slice3, slice3...) // 100, 200, 300,400, 500, 600 100, 200, 300,400, 500, 600
    fmt.Println("slice3", slice3)


    //切片的拷贝操作
    //切片使用copy内置函数完成拷贝,举例说明
    fmt.Println()
    var slice4 []int = []int{1, 2, 3, 4, 5}
    var slice5 = make([]int, 10)
    copy(slice5, slice4)
    fmt.Println("slice4=", slice4)// 1, 2, 3, 4, 5
    fmt.Println("slice5=", slice5) // 1, 2, 3, 4, 5, 0 , 0 ,0,0,0
}
切片的遍历

5.3 string切片处理

package main
import (
    "fmt"
)

func main() {

    //string底层是一个byte数组,因此string也可以进行切片处理
    str := "hello@atguigu"
    //使用切片获取到 atguigu
    slice := str[6:] 
    fmt.Println("slice=", slice)

    //string是不可变的,也就说不能通过 str[0] = 'z' 方式来修改字符串 
    //str[0] = 'z' [编译不会通过,报错,原因是string是不可变]

    //如果需要修改字符串,可以先将string -> []byte / 或者 []rune -> 修改 -> 重写转成string
    // "hello@atguigu" =>改成 "zello@atguigu"
    // arr1 := []byte(str) 
    // arr1[0] = 'z'
    // str = string(arr1)
    // fmt.Println("str=", str)

    // 细节,我们转成[]byte后,可以处理英文和数字,但是不能处理中文
    // 原因是 []byte 字节来处理 ,而一个汉字,是3个字节,因此就会出现乱码
    // 解决方法是 将  string 转成 []rune 即可, 因为 []rune是按字符处理,兼容汉字

    arr1 := []rune(str) 
    arr1[0] = ''
    str = string(arr1)
    fmt.Println("str=", str)
}
stringslice

5.4 sliceforrange

package main
import (
    "fmt"
)

func main() {

    //使用常规的for循环遍历切片
    var arr [5]int = [...]int{10, 20, 30, 40, 50}
    //slice := arr[1:4] // 20, 30, 40
    slice := arr[1:4]
    for i := 0; i < len(slice); i++ {
        fmt.Printf("slice[%v]=%v ", i, slice[i])
    }

    fmt.Println()
    //使用for--range 方式遍历切片
    for i, v := range slice {
        fmt.Printf("i=%v v=%v \n", i, v)
    }

    slice2 := slice[1:2] //  slice [ 20, 30, 40]    [30]
    slice2[0] = 100  // 因为arr , slice 和slice2 指向的数据空间是同一个,因此slice2[0]=100,其它的都变化

    fmt.Println("slice2=", slice2)
    fmt.Println("slice=", slice)
    fmt.Println("arr=", arr)

    fmt.Println()

    //用append内置函数,可以对切片进行动态追加
    var slice3 []int = []int{100, 200, 300}
    //通过append直接给slice3追加具体的元素
    slice3 = append(slice3, 400, 500, 600)
    fmt.Println("slice3", slice3) //100, 200, 300,400, 500, 600

    //通过append将切片slice3追加给slice3
    slice3 = append(slice3, slice3...) // 100, 200, 300,400, 500, 600 100, 200, 300,400, 500, 600
    fmt.Println("slice3", slice3)


    //切片的拷贝操作
    //切片使用copy内置函数完成拷贝,举例说明
    fmt.Println()
    var slice4 []int = []int{1, 2, 3, 4, 5}
    var slice5 = make([]int, 10)
    copy(slice5, slice4)
    fmt.Println("slice4=", slice4)// 1, 2, 3, 4, 5
    fmt.Println("slice5=", slice5) // 1, 2, 3, 4, 5, 0 , 0 ,0,0,0
}
sliceforrange

原理解析:

 

posted @ 2021-08-14 21:41  风hua  阅读(65)  评论(0)    收藏  举报