数组
func main() {
//数组的定义方式
//[0,0,0]
var nums1 [3]int
nums2 := [3]int{
1, 2, 3}
// 如果要让编译器判断我们有几个元素,要用... 没有...是切片
nums3 := [...]int{
3, 4, 5}
fmt.Println(nums1, nums3, nums2)
// 遍历方式
// 第一种
for i:=0;i<len(nums3);i++{
fmt.Println(nums3[i])
}
// i为索引
for i :=range nums2{
fmt.Println(i)
}
// i为索引 v为值
for i, v:=range nums2{
fmt.Println(i,v)
}
// 丢弃索引
for _, v:=range nums2{
fmt.Println(v)
}
// 数组是值类型
}
// 数组是值类型,作为参数会拷贝整个数组
// [3]int [5]int是不同的类型,这个函数只能传入[5]int类型
// 数组是值类型,所以在函数内修改数组的值并不会影响到实参
func printArray(arr [5]int) {
arr[3] = 100 //不会影响到实参
}
func printArray2(arr *[5]int) {
//传入指针
arr[3] = 100 //这样就可以改变值,很灵活,不用在arr前面加上*
(*arr)[3] = 100 // 这样也可以
}
// 在go语言中一般不直接使用数组
切片-Slice
func main() {
// 切片 左开右闭
arrList := [7]int{
1,2,3,4,5,6,7}
arr := arrList[:] // 定义一个切片
arr1 := arrList[2,6] // arr1 [3,4,5,6]
arr1[0] = 22 //arrList [1,2,22,4,5,6,7]
sliceLearn(arr) //arrList [22,2,22,4,5,6,7]
//切片可以对切片处理
arr3 := arr1[1,3] //arr3 [4,5]
arr4 := arr3[0:4] // arr4 [4,5,6,7]
}
// slice 切片
// slice相当于数组的一个view
// slice 定义 arr []int
func sliceLearn(arr []int){
arr[0]=22 // 会改变值,而且会影响实参数
}
//Slice本身没有数据,是对底层array的一个view
// slice可以向后扩展,但不可以向前扩展
struct {
ptr // 指向数组中切片第一个元素的指针
len //slice视图的数据
cap // 底层数组的长度
}
// reslice 扩展不能超过cap的长度 s[i] 不能超过len的长度
// %v value的值 %T 类型
// 一个切片s可以扩展到他的大小上限:s = s[:cap(s)], 如果再扩大的话就会报运行时错误
// 向Slice添加元素
// 添加元素时如果超过了cap,系统会重新分配更大的底层数组 然后把值拷贝过去
func main() {
arr := [6]int{
1, 2, 3, 4, 5, 6}
slice1 := arr[2:5]
slice2 := append(slice1, 11) // 把6变成11
slice3 := append(slice2, 12) //分配一个更长的arr 然后slice3 view他
fmt.Println(slice1, slice2, slice3) // [3 4 5] [3 4 5 11] [3 4 5 11 12]
fmt.Println(arr) //[1 2 3 4 5 11]
// 由于是值传递,所以必须接收append的值
// 直接创建slice
var s []int // nil
s1 := []int{
2, 3, 4, 5} // 这样也可以
s2 := make([]int, 16)
s3 := make([]int, 16, 32)
for i := 0; i < 100; i++ {
printSlice(s)
s = append(s, 2*i)
}
fmt.Println(s)
copy(s2,s1) // dst scr
//删除一个元素
s2 = append(s2[:3],s2[4:]...)//把位置为3的删掉
s2 = s2[1:] //删除头
s2 = s2[:len(s2)-1] //删除尾
}
func printSlice(s []int) {
fmt.Printf(" len=%d, cap=%d\n", len(s), cap(s))
// len=6, cap=8
// len=7, cap=8
// len=8, cap=8
// len=9, cap=16
// len=10, cap=16
}
Map
map[k]V
map[k]map[k2]V
func main() {
m1 := map[string]string{
"aa": "bb",
"bb": "cc",
}
m2 := make(map[string]string) // m2 == empty map
var m3 map[string]string //m3 == nil
fmt.Println(m1, m2, m3) //map[aa:bb bb:cc] map[] map[]
//遍历 无序 每次顺序不一样
for k, v := range m1 {
fmt.Println(k, v)
}
// key
for k := range m1 {
fmt.Println(k)
}
// 打印一个不存在的key 会是zero value
fmt.Println(m1["abc"])
courseName, ok := m2["abc"] // 第二个为true 表示值存在,false表示不存在
fmt.Println(courseName, ok) // false
delete(m1,"abc") // 删除元素
}
- 创建:make(map[string]int)
- 获取元素 m[key]
- key不存在时获取value类型的初始值
- 用value, ok := m[key]来判断是否存在key
- 用delete删除一个key
- map遍历不保证顺序,可以用len来获取个数
- map使用的是哈希表,key必须可以比较相等
- 除了slice, map, function的内建类型都可以作为key
- struct类型不包含上述字段,也可以作为key
- 每个rune是4个字节,转rune 不是对原有的内存存的东西进行解释,而是重新开一个内存,然后解释后存起来
rune
- rune相当于go的char
- 使用range遍历pos(索引不连续),rune(索引连续)对
- 使用utf8.RuneCountInString获得字符数量
- 使用len获得字节长度
- 使用[]byte获得字节
func main() {
s := "yes!肖小小最棒"
fmt.Printf("%s\n", []byte(s)) //yes!肖小小最棒
for _, b := range []byte(s) {
// utf-8 可变长
fmt.Printf("%X ", b) //79 65 73 EF BC 81 E8 82 96 E5 B0 8F E5 B0 8F E6 9C 80 E6 A3 92
}
fmt.Println()
for i, ch := range s {
// ch is a rune
// i为索引 第几个字节开始 ch为unicode编码
//(0,79)(1,65)(2,73)(3,FF01)(6,8096)(9,5C0F)(12,5C0F)(15,6700)(18,68D2)
fmt.Printf("(%d,%X)", i, ch)
}
fmt.Println()
// 9
fmt.Println(utf8.RuneCountInString(s))
bytes := []byte(s)
for len(bytes) > 0 {
ch, size := utf8.DecodeRune(bytes) // ch is rune size 为ch的字节长度
bytes = bytes[size:]
fmt.Printf("%c", ch)
}
fmt.Println()
for i, ch := range []rune(s) {
// 下标连续
// (0,y)(1,e)(2,s)(3,!)(4,肖)(5,小)(6,小)(7,最)(8,棒)
fmt.Printf("(%d,%c)", i, ch)
}
fmt.Println()
}