文章目录
一、数组
1.1 数组的定义
定义:var 数组名 [数组大小]数据类型
案例:
func main() {
var arr [3]int
fmt.Println(arr)
fmt.Printf("arr的地址是=%p,arr[0]的地址是=%p", &arr,&arr[0])
}
数组在内存布局:
- 数组的地址可以通过数组名来获取
&arr
- 数组的第一个元素的地址,就是数组的首地址
- 数组的各个元素的地址间隔是依据数组的类型决定,比如
int64 -> 8 int32->4
1.2 数组的初始化
func main() {
var arr1 [3]int = [3]int{1, 2, 3}
fmt.Println(arr1)//[1 2 3]
var arr2 = [3]int{4, 5, 6}
fmt.Println(arr2)//[4 5 6]
var arr3 = [...]int{1, 2, 3}
fmt.Println(arr3)//[1 2 3]
var arr4 = [...]int{1:1, 0:2, 2:3}
fmt.Println(arr4)//[2 1 3]
arr5 :=[...]int{1,2,3}
fmt.Println(arr5)//[1 2 3]
}
1.3 数组的遍历
①常规
func main() {
arr := [3]int{1, 2, 3}
for i := 0; i < len(arr); i++ {
fmt.Printf(" %d", arr[i])
}
}
②for-range
语法:
for index, value := range arr {
...
}
说明:
- 第一个
index
是数组的下标 - 第二个
value
即对应的值 - 若不需要
index
,可以用_
替换
案例:
func main() {
arr := [3]int{4, 5, 6}
for i, v := range arr {
fmt.Printf("arr[%d]=%d ", i, v) //arr[0]=4 arr[1]=5 arr[2]=6
}
}
1.4 数组使用的注意事项和细节
- 数组是多个相同类型数据的组合,一个数组一旦声明、定义了,其长度是固定的, 不能动态变化
var arr []int
这时arr
就是一个slice
切片- 数组创建后,如果没有赋值,会使用默认值。数组类型默认值:0,字符串类型默认值:"",
bool
默认值:0 - 数组下标必须在指定范围内使用,否则报
panic
:数组越界 - Go 的数组属值类型, 在默认情况下是值传递, 因此会进行值拷贝。若要修改原来的数组,可以使用引用传递(指针方式)
二、切片
2.1 切片的定义
切片(slice
)是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制。切片的使用和数组类似,切片的长度是可以变化的,因此切片是一个可以动态变化数组。
定义:var 切片名 []类型
func main() {
arr := [...]int{1, 2, 3, 4, 5}
slice := arr[1:3]
fmt.Printf("slice的类型:%T\n", slice)//slice的类型为[]int
fmt.Println("slice的元素:", slice)//slice的元素: [2 3]
fmt.Println("slice的元素个数:", len(slice))//slice的元素个数: 2
fmt.Println("slice的容量:", cap(slice))//slice的容量: 4
}
切片在内存布局:
可以看出,切片是一个引用类型,指向了某个数组。
2.2 切片的使用
①定义一个切片,然后让切片去引用一个已经创建好的数组
func main() {
arr := [...]int{1, 2, 3, 4, 5}
slice := arr[1:3]
fmt.Println("slice的元素:", slice)//slice的元素: [2 3]
}
②通过make 来创建切片
基本语法:var 切片名 []type = make([]type, len, [cap])
参数说明:
type
: 就是数据类型
len
: 大小
cap
:指定切片容量,可选, 如果你分配了cap
,则要求cap
>=len
案例:
func main() {
slice := make([]int, 5, 10)
slice[0] = 1
slice[1] = 2
fmt.Println(slice)//[1 2 0 0 0]
}
③直接指定具体数组
func main() {
slice := []int{1, 2, 3}
fmt.Println(slice) //[1 2 3]
}
2.3 切片的遍历
①常规
func main() {
arr := [...]int{1, 2, 3, 4, 5}
slice := arr[1:3]
for i := 0; i < len(slice); i++ {
fmt.Printf("%d ", slice[i]) //2 3
}
}
②for-range
func main() {
arr := [...]int{1, 2, 3, 4, 5}
slice := arr[1:3]
for _, v := range slice {
fmt.Printf("%d ", v)//2 3
}
}
2.4 切片使用的注意事项和细节
- 切片初始化时,仍然不能越界。范围在
[0-len(arr)]
之间,但是可以动态增长
var slice = arr[0:end]
可以简写var slice = arr[:end]
var slice = arr[start:len(arr)]
可以简写:var slice = arr[start:]
var slice = arr[0:len(arr)]
可以简写:var slice = arr[:]
- 用
append
内置函数,可以对切片进行动态追加(对数组进行动态扩容)
func main() {
slice := make([]int, 2, 2)
slice[0] = 1
slice[1] = 2
slice = append(slice, 3, 4)
fmt.Println(slice) //[1 2 3 4]
}
- 切片是引用类型,所以在传递时,遵守引用传递机制
func main() {
var slice []int
arr := [...]int{1, 2, 3}
slice = arr[:]
slice2 := slice
slice2[0] = 4
fmt.Println(arr)
fmt.Println(slice)
fmt.Println(slice2)
}
2.5 string 和 slice
string
底层是一个byte
数组,因此string
也可以进行切片处理
func main() {
str := "Hello Go"
slice := str[:3]
fmt.Println(slice)//Hel
}
string
是不可变的,不能通过str[0] = 'z'
方式来修改字符串。可以先将string
转为[]byte
、[]rune
进行修改。
func main() {
str := "Hello Go"
arr := []byte(str)
arr[0] = 'F'
str = string(arr)
fmt.Println(str) //Fello Go
arr2 := []rune(str)
arr2[0] = 'C'
str = string(arr2)
fmt.Println(str) //Cello Go
}