数组
数组可以存放多个同一类型数据
。数组也是一种数据类型,在Go中,数组是值类型
。
例子
package main
import "fmt"
func main() {
//定义一个数组
var arr [5]int
//给数组的每个元素赋值
arr[0] = 3
arr[1] = 6
arr[2] = 9
arr[3] = 12
arr[4] = 15
for i := 0; i < len(arr); i++ {
fmt.Printf("索引[%d]的值为:%d\n",i,arr[i])
}
}
数组定义
var 数组名 [数组大小]数据类型
例如
var a [10]int
进行赋初始值
a[0] = 23
a[1] = 30
....
其下标也是从0开始。
数组的地址可以通过数组名来获取 &arr
数组的第一个元素的地址就是数组的首地址
数组的各个元素的地址间隔是依据数组的类型决定的,比如 int64 ->8 int32 ->4
func main(){
var arr [3]int
fmt.Println(arr)
arr[0] = 1
arr[1] = 2
arr[2] = 3
fmt.Println(arr)
fmt.Printf("arr的地址=%p arr[0]的地址=%p arr[1]的地址=%p arr[1]的地址=%p",&arr,&arr[0],&arr[1],&arr[2])
}
数组初始化
四种初始化数组的方法
//方法一
var arr1 [3]int = [3]int{1,2,3}
fmt.Println("arr1=",arr1)
//方法二
var arr2 = [3]int{1,2,3}
fmt.Println("arr2=",arr2)
//方法三
//[...]是规定的写法
var arr3 = [...]int{1,2,3}
fmt.Println("arr3=",arr3)
//方法四
var arr4 = [...]int{1:300, 0:500, 2:90}
fmt.Println("arr4=",arr4)
数组的遍历
方法一:常规遍历
var arr [3]int
for i:=0; i< len(arr); i++{
fmt.Printf("arr[%d]=%v\n",i, arr[i])
}
方法二:for-range结构遍历
func main(){
str := [...]string{"小名","小白","小黑"}
for i,v := range str{
fmt.Printf("i=%v v=%v\n",i,v)
fmt.Printf("str[%d]=%v\n",i,str[i])
}
for _, v := range str{
fmt.Printf("元素的值=%v\n",v)
}
}
对上述for-range结构进行说明:
- 第一个返回的值是数组的下标,也就是上述的i
- 第二个是在该下标位置的值,也就是上述的v
- i和v仅在for循环内部可见的局部变量
- 对数组进行遍历的时候,如果不想使用下标i,可以直接把下标i换成_
- i和v的名称不是固定的,可自己定义
扩展
从终端循环输入5个数字,保存到float64数组中,并输出
var num [5]float64
for i:=0; i< len(num); i++{
fmt.Printf("请输入第%d个元素的值\n",i+1)
fmt.Scanln(&num[i])
}
for i:=0; i < len(num); i++{
fmt.Printf("num[%d]=%v\n",i, num[i])
}
注意事项
- 数组是多个相同类型数据的组合。一旦定义了,长度是固定不变的。
- 数组中的元素可以是任何类型的数据,包括值类型和引用类型。
- 数组创建后,如果没有赋值,其值就为默认值
数值类型数组:默认值为0
字符串数组:默认值为""
bool数组:默认值为false - 数组的下标是从0开始的。
- 数组下标必须在指定范围内使用,否则会报错。
- 如果想在其他函数中修改原来的数组,可以使用引用传递(指针方式)
arr := [3]int{1,2,3}
test(&arr)
fmt.Println("arr=",arr)
func test(arr *[3]int){
(*arr)[0] = 32
}
切片
切片(slice)是数组的一个引用,所以切片是引用类型
;切片的长度是可以变化的,因此切片是一个可以动态变化数组
。
定义
var 切片名 []类型
如: var sli []int
func mian(){
var arr [5]int = [...]int{1,2,3,4,5}
//定义一个切片
sli := arr[1:3]
//上面表示切片sli引用到arr这个数组,引用arr从下标1开始到下标3,但是不包含3
fmt.Println("arr=",arr)
fmt.Println("sli的元素是=",sli) // 2,3
fmt.Println("sli的元素个数=",len(sli)) //2
fmt.Println("sli的容量=",cap(sli)) //切片的容量是可以动态变化的
}
切片使用
方式一:定义一个切片,然后让切片去引用一个已经创建好的数组,如上述的
var arr [5]int = [...]int{1,2,3,4,5}
//定义一个切片
sli := arr[1:3]
方式二:通过make
来创建切片
其语法:var 切片名 []type = make([]type,len,[cap])
参数说明:type就是数据类型,len是大小,cap是指定切片容量,为可选参数,使用要确保cap>=len
例子:
var sli []str = make([]string, 5, 10)
sli[1] = "xia"
sli[3] = "ming"
fmt.Println(sli)
fmt.Println("sli的size=",len(sli))
fmt.Println("sli的cap=",cap(sli))
通过make方式创建切片可以指定切片的大小和容量;
没有给切片的各个元素赋值,就会使用默认值,默认值和数组的一致;
通过make方式创建的切片对应的数组是由make底层维护,对外不可见,只能通过slice去访问各个元素。
方式三:定义一个切片,直接指定具体数组
var sli []string = []string{"aa","bb","cc"}
fmt.Println("sli=",sli)
fmt.Println("sli的size=",len(sli))
fmt.Println("sli的cap=",cap(sli))
注意:方式一和方式二有什么区别?
方式一是直接通过引用数组,这个数组是事先存在的,程序员可见的。
方式二是通过make来创建切片,make也会创建一个数组,是由切片在底层进行维护,程序员是不可见的。
切片遍历
切片的遍历也是有两种方式:
- for循环常规方式
- for-range结构遍历
func main(){
//常规for
var arr [5]int = [...]int{1,2,3,4,5}
sli := arr[1:4]
for i := 0; i< len(sli); i++{
fmt.Printf("sli[%v]=%v",i,sli[i])
}
fmt.Println()
//使用for-range方式
for i, v :=range sli{
fmt.Printf("i=%v v=%v",i,v)
}
}
切片追加
使用其内置函数append
,可以对切片进行动态追加
var sli []int = []int{1,2,3}
sli = append(sli,4,5,6)
fmt.Println("sli=",sli)
//也可通过append将切片sli追加给sli
sli = append(sli,sli...) //1,2,3,4,5,6 1,2,3,4,5,6
fmt.Println("sli=",sli)
切片的拷贝
切片使用copy
内置函数完成拷贝
var sli1 []int = []int{1,2,3,4,5}
var sli2 = make([]int,10)
copy(sli2,sli1)
fmt.Println("sli1=",sli1) //1,2,3,4,5
fmt.Println("sli2=",sli2) //1,2,3,4,5,0,0,0,0,0
sli1和sli2的数据空间是独立,相互不影响,拷贝执行后sli1的值不变
切片对string操作
string底层是一个byte数组,因此string也可以进行切片:
func main(){
str := "helloworld"
sli := str[6:]
fmt.Println("sli=",sli)
}
如果需要修改字符串
//如果需要修改字符串,可以先将string -> []byte 或者 []rune -> 修改 -> 重写转成string
//"helloworld"改成"aelloworld"
arr := []byte(str)
arr[0] = 'a'
str = string(arr)
fmt.Println("str=",str)
//注意:转成[]byte后,可以处理英文和数字,但是不能处理中文
//因为[]byte是一个字节处理,而一个汉字是3个字节,会出现乱码
//解决方法是将string转成[]rune即可,因为[]rune是按字符处理,兼容汉字
arr2 := []rune(str)
arr2[0] = '你'
str = string(arr2)
fmt.Println("str=",str)
注意事项
- 切片初始化时,仍然不能越界。范围在[0-len(arr)]之间,但是可以动态追加。
- cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。
- 切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用。
- 切片可以继续切片
sli2 := sli[1:2]