复合类型
分类
类型 | 名称 | 长度 | 默认值 | 说明
pointer | 指针 | | nil |
array | 数组 | | 0 |
slice | 切片 | | nil | 引用类型
map | 字典 | | nil | 引用类型
struct | 结构体 | | |
指针
指针是代表某个内存地址的值,这个内存地址往往是在内存中存储的另一个变量的值的起始位置。
基本操作
func main() {
var a int = 10
// 每个变量有两层含义:变量的内存和变量的地址
fmt.Printf("a = %d\n", a) // 变量的内存
fmt.Printf("a = %v\n", &a) // 变量的地址
// 保存某个变量的地址,需要指针类型
// *int 用以保存 int 的地址
// **int 用以保存 *int 的地址
var p *int
p = &a // 指针变量指向谁,就把谁的地址赋值给指针变量
*p = 666 // *p操作的不是p的内存,而是p所指向的内存(既是a)
}
不要操作没有合法指向的内存。
new函数
var p *int //指向一个合法内存
p = new(int) // p是*int,指向int类型
*p = 666
q := new(int) // 自动推导类型
*q = 777
地址传递
func swap(p1, p2 *int) {
*p1, *p2 = *p2, *p1
}
func main() {
a, b := 10, 20
swap(&a, &b)
}
数组
为什么需要数组
数组:同一类型数据的集合。
通过下标操作数组,从0开始,到 len()-1
数组定义
func main() {
// 定义一个数组,[10]int和[5]int是不同类型
// [数字],这个数字作为数组元素个数
var a [10]int
var b [5]int
// 注意:定义数组时,指定的数组元素个数必须是常量
// 数组下标可以是变量或常量
}
数组初始化
初始化:声明定义的同时赋值
func main() {
// 全部初始化
var a [5]int = [5]int{1, 2, 3, 4, 5}
b := [5]int{1, 2, 3, 4, 5}
// 部分初始化,没有初始化的元素自动赋值为0
c := [5]int{1, 2, 3}
// 指定某个元素初始化
d := [5]int{2: 10, 4: 20 }
}
二维数组
var a [3][4]int
var b [3][4]int
b := [3][4]int{{1,2,3,4}, {5,6,7,8}, {9,10,11,12}}
// 部分初始化,没有初始化的为0
b := [3][4]int{{1,2,3,4}, {5,6,7,8}, {9,10}}
数组比较和赋值
只支持 == 和 != 的比较,用于比较两个数组类型、每个元素都一样。
map
map(映射、字典)是一种内置的数据结构,它是一个无序的key-value对的集合。
map创建和初始化
map只有len,没有cap
// 先声明,后赋值
var m1 map[int]string
// 通过make创建,可以指定长度,只是指定了容量,但是数据为空
// 超出预设容量时,会自动扩容
m2 := make(map[int]string, 10)
// 键名是唯一的
info := map[int]string{
110: "mike",
111: "yoyo",
112: "lily"
}
map常用操作
赋值
m1 := map[int]string{1:"mike", 2:"yoyo"}
// 重复键名赋值,会进行覆盖
m1[1] = "c++"
// 追加元素时,map底层自动增加内存,和append类似
m1[3] = "go"
遍历
m := map[int]string{1:"mike", 2:"yoyo", 3:"go"}
// 第一个返回值为key,第二个返回值为value,遍历结果是无序的
for key, value := range m {
fmt.Printf("%d ====> %s\n", key, value)
}
判断key是否存在
// 第一个值为key所对应的value,第二个返回值为key是否存在的状态,true或者false
value, ok := m[1]
删除
// 删除m中key为1的内容
delete(m,1)
map做参数
map做函数参数时,是引用传递。
结构体
结构体普通变量初始化
// 定义一个结构体类型
type Student struct {
id int
name string
sex byte
age int
attr string
}
func main(){
// 顺序初始化,每个成员都必须初始化
var s1 Student = Student{1, "mike", 'm', 18, "bj"}
// 指定成员初始化,没有初始化的成员自动赋值为0
s2 := Student{name: "mike", addr:"bj"}
}
结构体指针变量初始化
// 定义一个结构体类型
type Student struct {
id int
name string
sex byte
age int
attr string
}
func main(){
var p1 *Student = &Student{1, "mike", 'm', 18, "bj"}
p2 := &Student{name: "mike", addr:"bj"}
}
结构体普通变量成员的使用
// 定义一个结构体类型
type Student struct {
id int
name string
sex byte
age int
attr string
}
func main(){
// 定义一个结构体普通变量
var s Student
// 操作成员需要使用点(.)运算符
s.id = 1
s.name = "mike"
s.sex = 'm' // 字符
s.sddr = "bj"
}
结构体指针变量成员的使用
// 定义一个结构体类型
type Student struct {
id int
name string
sex byte
age int
attr string
}
func main(){
// 1、指针有合法指向后,才操作变量
// 先定义一个结构体普通变量
var s Student
// 再定义一个指针变量,保存s的地址
var p1 *Student
p1 = &s
// 通过指针操作成员,p1.id和(*p1).id完全等价,只能使用点(.)运算符
p1.id = 18
(*p1).name = "mike" // 与上面等价
// 2、通过new来申请一个结构体
p2 := new(Student)
p2.id = 1
p2.name = "mike"
}
结构体比较和赋值
// 定义一个结构体类型
type Student struct {
id int
name string
sex byte
age int
attr string
}
func main(){
s1 := Student{1, "mike", 'm', 18, "bj"}
s2 := Student{1, "mike", 'm', 18, "bj"}
s3 := Student{2, "mike", 'm', 18, "bj"}
fmt.Println("s1 == s2 ",s1 == s2)
fmt.Println("s1 == s3 ",s1 == s3)
// 同类型的两个结构体可以相互赋值
var tmp Student
tmp = s3
}
结构体做函数参数
可以值传递和地址传递。
可见性
如果想使用别的包的函数、结构体类型、结构体成员,
函数名、类型名、结构体成员变量名的首字母必须大写、可见,
如果首字母是小写,只能在同一个包里使用。
用谁谁首字母大写