基础语法2
数组
Go语言中的数组与C/C++语言中类似
声明方式与先前的变量声明类似,与C/C++区别在于类型声明在数组大小声明之后,如下:
创建长度为5,类型为int型的数组var a [5]int
同样可以通过下标索引和赋值:
- 下标索引
a[4] = 100 - 初始化赋值
b := [5]int{1, 2, 3, 4, 5}
切片
在C++中我们通常很少使用单纯的数组存放数据,而是调用STL中的vector容器。原因很简单,vector不仅长度可变,而且封装了增删改查的方法。 在Go中也是如此,由于数组长度不可变,在实际应用中通常使用切片。
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
- 切片可以看作是可变长度数组。
- ==make==创建切片
s := make([]string, 3) - append添加元素
s = append(s,"d") - copy复制切片
c := make([]string, len(s))
copy(c, s)
- 类似python的切片
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
区别在于,在Go语言中的切片不像python那样支持负数索引,想要取到末尾的元素只能通过len函数。 个人觉得这一点是比较遗憾的。我很好奇地在网上查阅为什么Go不支持负数索引。原因在于切片实际上还是依赖于原始数组,当进行切片操作时,切片的底层数组指针会根据指定范围和容量创建一个新的切片。如果允许切片使用负数索引,这将导致切片底层数组指针无法正确计算从而可能导致越界或其他不可预测的错误。
map
map在许多其他语言中我习惯用键值对的方式称呼它们
map通过==make==创建
m := make(map[string]int)
由代码中可得创建了一个键Key为string类型,值value为int类型的map。通过Key访问元素,访问过程中会返回布尔值以告知是否存在该元素r, ok := m["unknow"].通过delete删除元素delete(m, "one")
需要注意的是在Go中对map的遍历是随机的,没有顺序。曾经在使用map过程中我希望它是有序的,在互联网上发现的确有人与我有相同的需求,并且有包orderedmap。
该包支持按以下需求排序:
- 添加顺序
- key字典升降序
- value字典升降序
range
range关键字常用于对数组、map数据结构的遍历,与for循环搭配使用
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
fmt.Println(sum) // 9
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v) // b 8; a A
}
函数
Go语言函数定义格式:
func func_name( [parameter list] ) [return_types] {
//函数体
}
- func关键字开始声明函数
- func_name为函数名称
- parameter list参数列表
- return_types为函数返回值类型,不需要返回值时可选
Go函数较有特色的是可以返回多个值,如:
func swap(x, y string) (string, string) {
return y, x
}
指针
是C/C++指针的极简版,主要用于在函数中修改参数的值
结构体
在Go语言中结构体是带类型字段的集合
type user struct {
name string
password string
}
用结构体名称初始化结构体变量
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
结构体方法
func checkPassword(u user, password string) bool {
return u.password == password
}
将全局函数转换为user结构体的方法
func (u user) checkPassword(password string) bool {
return u.password == password
}
可以定义函数绑定在一个结构体上,类似C/C++中的类成员函数,在初始Go语言时知道Go并没有类的概念,但支持面向对象。结构体方法就是体现面向对象的一种实现形式
错误处理
常用函数返回值返回error类型的错误信息,用errors.New()创建
字符串处理
字符串操作
下列方法包含在==strings包==中:
- Contains:是否含有子字符串
- Count:统计字符串中指定字符出现的次数
- Index:查找子串位置
- Join:连接字符串
- ......
字符串序列化
方法都类似。其中fmt.Printf与C/C++中的printf不同在于 fmt.Printf只需要==%v==即可输出任意类型的变量值
s := "hello"
n := 123
p := point{1, 2}
fmt.Printf("s=%v\n", s) // s=hello
fmt.Printf("n=%v\n", n) // n=123
fmt.Printf("p=%v\n", p) // p={1 2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
==%+v==,==%#v==则可以输出更详细的变量信息