09【保姆级】-GO语言的数组和切片

09【保姆级】-GO语言的数组

  • 一、数组
    • 1.1 数组定义
    • 1.2 数组的使用
    • 1.3 数组的遍历
    • 1.4 数组的应用案例
  • 二、切片
    • 2.1 切片的介绍
    • 2.2 切片的原理和细节
    • 2.3 切片的三种使用
    • 2.4 切片的遍历
    • 2.5 切片和string

之前我学过C、Java、Python语言时总结的经验:

  1. 先建立整体框架,然后再去抠细节。
  2. 先Know how,然后know why。
  3. 先做出来,然后再去一点点研究,才会事半功倍。
  4. 适当的囫囵吞枣。因为死抠某个知识点很浪费时间的。
  5. 对于GO语言,切记遵守语法格式规则。(例如python语言、例如SpringBoot框架等)
    解释:某些知识点,就是很难了解,那么先做出来,然后继续向前学习,可能在某个时间点我们就会恍然大悟。

一、数组

1.1 数组定义

数组可以存放多个同一类型数据。数组也是一种数据类型,在 Go 中,数组是值类型。

初始化的四种方式:

var arr01 [3]int = [3]int{1, 2, 3}
var arr02 = [3]int{1, 2, 3}
var arr03 = [...]int{1, 2, 3}
var arr04 = [...]int{1: 111, 0: 001, 2: 222}
fmt.Println("arr04=", arr04) // arr04= [1 111 222]
// 设置排序顺序

数组的首地址 也就是 数组第一个元素的地址。第二个元素的地址是:首地址+数组类型的占用的字节数。

var arr [5]float64
fmt.Printf("首地址是:%p,首元素地址是:%p,第二个元素的地址是:%p", &arr, &arr[0], &arr[1])
// 首地址是:0xc042076030,首元素地址是:0xc042076030,第二个元素的地址是:0xc042076038

1.2 数组的使用

func main() {
	var arr [5]float64
	arr[0] = 1.2
	arr[1] = 2.2
	arr[2] = 21.2
	arr[3] = 3.2
	arr[4] = 4.2
	num := 0.0
	for i := 0; i < len(arr); i++ {
		num += arr[i]
	}
	fmt.Println("num=", num)  //n um= 32
}

1.3 数组的遍历

方式一常规方式:如上述章节方式

方式二:for-range结构遍历:用来遍历访问数组的元素

for index,value :=range array01{

}
  1. 第一个返回值 index是数组的下标
  2. 第二个value是在该下标位置的值
  3. 他们都是仅在for循环内部可见的局部变量
  4. 遍历数组元素的时候,如果不想使用下标index,可以直接把下标index标为下划线_
  5. index和value 的名称不是固定的,即程序员可以自行指定,一般命名为index 和value
arr := [...]string{"张三", "lisi", "王五", "赵六"}
for i, s := range arr {
	fmt.Println("元素索引是:", i, "元素是:", s)
}
元素索引是: 0 元素是: 张三
元素索引是: 1 元素是: lisi
元素索引是: 2 元素是: 王五
元素索引是: 3 元素是: 赵六

----

arr := [...]string{"张三", "lisi", "王五", "赵六"}
for _, s := range arr {
	fmt.Println("元素是:", s)
}
元素是: 张三
元素是: lisi
元素是: 王五
元素是: 赵六

  1. 数组的下标是从0开始的。
  2. 数组下标必须在指定范围内使用,否则报 panic: 数组越界,比如var arr[5]int 则有效下标为 0-4
  3. Go的数组属值类型,在默认情况下是值传递, 因此会进行值拷贝。数组间不会相互影响
  4. 如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)[先体验下,画示意图]
---值传递: 在test栈中会赋值arr的数据
func main() {
	arr := [...]string{"11", "22", "33", "444"}

	testArr(arr)
	fmt.Println(arr) //  [11 22 33 444]
}

func testArr(arr [4]string) {
	arr[0] = "9999"
}

--- 地址传递:在test栈中会直接指向arr数组的数据。
// 所以可以改变数组中的元素
func main() {
	arr := [...]string{"11", "22", "33", "444"}

	testArr(&arr)
	fmt.Println(arr)  //  [9999 22 33 444]
}

func testArr(arr *[4]string) {
	arr[0] = "9999"
}

1.4 数组的应用案例

遍历数组从A加到Z,然后遍历输出:

func main() {

	var arr [26]byte
	for i := 0; i < 26; i++ {
		arr[i] = 'A' + byte(i)
	}
	fmt.Println(arr)
	// [65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90]
	for _, v := range arr {
		fmt.Printf("%c ", v)
	}
	//  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
}

二、切片

个数不确定时,可以使用切片。

2.1 切片的介绍

  1. 切片的英文是 slice
  2. 切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制
  3. 切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度 len(slice)都一样
  4. 切片的长度是可以变化的,因此切片是一个可以动态变化数组。
  5. 切片定义的基本语法
    var 切片名[类型]
    比如: var a I int

2.2 切片的原理和细节

切片是有三部分组成:

  • 指向数组的地址
  • 指向数组的长度
  • 切片的容量长度
    09【保姆级】-GO语言的数组和切片_第1张图片
  1. 切片初始化时 var slice arr[startlndex:endIndex]。 说明: 从arr数组下标为startIndex,取到 下标为endIndex的元素(不含arrendindex).
var arr = [5]int{10, 20, 30, 40, 50}
slice2 := arr[1:4] //  20, 30, 40,

如果想要取 slice2[3] 是取不到的,因为会越界异常
slice2[0] = 20
slice2[1] = 30
slice2[2] = 40
  1. 切片初始化时,仍然不能越界。范围在 [0-len(arr)] 之间,但是可以动态增长
    1. var slice = arr[O:end] 可以简写 var slice = arr[:end]
    2. var slice = arr[start:len(arr)] 可以简写: var slice = arr[start:]
    3. var slice = arr[0:len(arr)] 可以简写: var slice = arr[:]
  2. cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素
  3. 切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组或者make一个空间供切片来使用
  4. 切片可以继续切片。 例如下面的案例:全部都是指向一个数组地址
  5. 切片都是一个引用数组类型的,改变一个数据,全部都改变了
var arr = [5]int{10, 20, 30, 40, 50}
slice1 := arr[1:4] //  20, 30, 40,
slice 2 := slice1[:len(slice1)]  //  20, 30, 40,
slice 3 := slice1[1:2]  // 30
  1. 用append内置函数,可以对切片进行动态追加
  2. 切片append操作的本质就是对数组扩容
  3. go底层会创建一下新的数组newArr(安装扩容后大小)
  4. 将slice原来包含的元素拷贝到新的数组newArr
  5. slice 重新引用到newArr
  6. 注意newArr是在底层来维护的,程序员不可见
varsliceAppend []int = []int{100, 200, 300}
fmt.Println("追加前:", sliceAppend) //  追加前: [100 200 300]
sliceAppend = append(sliceAppend, 400, 500, 600)
fmt.Println("追加后:", sliceAppend) //  追加后: [100 200 300 400 500 600]
sliceAppend2 := append(sliceAppend, 400, 500, 600)
fmt.Println("追加后新的名字:", sliceAppend2) //  追加后: [100 200 300 400 500 600]
sliceAppend3 := append(sliceAppend, sliceAppend2...)
fmt.Println("追加一个切片:", sliceAppend3) //  追加一个切片: [100 200 300 400 500 600 100 200 300 400 500 600 400 500 600]

2.3 切片的三种使用

方式一:创建好的数组,进行切片

func main() {

	var arr [26]byte
	for i := 0; i < 26; i++ {
		arr[i] = 'A' + byte(i)
	}

	for _, v := range arr {
		fmt.Printf("%c ", v)
	}
	fmt.Println()
	//  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

	Myslice := arr[1:10]

	fmt.Printf("遍历Myslice切片元素: %c \n", Myslice) //slice: [66 67 68 69 70 71 72 73 74]
	fmt.Printf("切片的第一个元素:%p, 对应数组的地址是:%p", &Myslice[0], &arr[1])
	// 切片的第一个元素:0xc0420580a1, 对应数组的地址是:0xc0420580a1
}

内置的make来创作切片:
1)通过 make方式创建切片可以指定切片的大小和容量
2)如果没有给切片的各个元素赋值,那么就会使用默认值[int ,foat=> 0boo1 =string =false]
3)通过 make 方式创建的切片对应的数组是由 make 底层维护,对外不可见,即只能通过 slice 去访间各个元素

var slice []float64 = make([]float64 ,5, 10)

make(切片的类型,切片的大小,指定切片的容量大小)

内置的make来创作切片:

var strSlice []string = []string{"zhang", "lisi", "wangwu"}
fmt.Println("strSlice:", strSlice)
fmt.Println("strSlice, size:", len(strSlice))
fmt.Println("strSlice, cap:", cap(strSlice))
// strSlice: [zhang lisi wangwu]
// strSlice, size: 3
// strSlice, cap: 3

2.4 切片的遍历

for循环遍历

func main() {

	var arr = [5]int{10, 20, 30, 40, 50}
	slice2 := arr[1:4] //  20, 30, 40,
	for i := 0; i < len(slice2); i++ {
		fmt.Println("切片遍历:", slice2[i])
	}
	// 切片遍历: 20
	// 切片遍历: 30
	// 切片遍历: 40

> foreach 遍历
	for index, value := range slice2 {
		fmt.Println("index:", index, "value:", value)
	}
	// index: 0 value: 20
	// index: 1 value: 30
	// index: 2 value: 40
}

2.5 切片和string

  • string底层是一个byte数组,因此string也可以进行切片处理

将字符串进行切片处理

func main() {
	// 将字符串进行切片处理:
	str := "helloworld"
	sliceStr := str[0:5]
	fmt.Println(sliceStr) // hello
}
  • string是不可变的,也就说不能通过 str[o]=2 方式来修改字符串
  • 如果要修改字符串,需要先将字符串转为 []byte 切片 或者 []rune(按字符处理,兼容汉字) ->修改后,重新转成string
func main() {
	// 将字符串进行切片处理:
	str := "helloworld"
	
	arr1 := []byte(str)
	arr1[0] = 'H'
	str = string(arr1)
	fmt.Println(str) // Helloworld
}

--  中文处理:


func main() {
	// 将字符串进行切片处理:
	str := "helloworld"
	sliceStr := str[0:5]
	fmt.Println(sliceStr) // hello

	arr1 := []rune(str)
	arr1[0] = '中'
	str = string(arr1)
	fmt.Println(str) // 中elloworld
}

你可能感兴趣的:(golang,java,开发语言)