go 语言将数据类型分为四类,包括:基础类型,复合类型,引用类型和接口类型,其中
go 语言的引用类型包括:指针、切片、字典、函数、通道
go 语言的基本类型包括:数字、字符串、布尔、数组 及 接口类型
go 语言的复合数据类型:数组、结构体
int和uint的区别
int8的范围就是-128~127 有符号
uint的范围就是0~255 无符号
a := byte(255) //11111111 这是byte的极限, 因为 a := byte(256)//越界报错, 0~255正好256个数,不能再高了
b := uint8(255) //11111111 这是uint8的极限,因为 c := uint8(256)//越界报错,0~255正好256个数,不能再高了
c := int8(127) //01111111 这是int8的极限, 因为 b := int8(128)//越界报错, 0~127正好128个数,所以int8的极限只是256的一半
d := int8(a) //11111111 打印出来则是-0000001,int8(128)、int8(255)、int8(byte(255))都报错越界,因为int极限是127,但是却可以写:int8(a),第一位拿来当符号了
e := int8(c) //01111111 打印出来还是01111111
数组定义
var arr0 = [5]int{1, 2, 3}
for _, value := range arr0 {
fmt.Print(" ", value)
}
fmt.Println()
var arr1 = [...]int{7, 8, 9, 4, 5, 6}
for _, v := range arr1 {
fmt.Print(" ", v)
}
fmt.Println()
var str = [5]string{2: "hello", 4: "jacob"}
for i := 0; i < len(str); i++ {
fmt.Print(" ", str[i])
}
fmt.Println("\n", str[0] == "")
注:1.数组是值类型,赋值和传参会复制整个数组,而不是指针,因此改变副本的值不会改变原数组的值
2.值拷贝行为会造成性能问题,通常会建议使用 slice,或数组指针。
3.指针数组 [n]*T,数组指针 *[n]T。
切片
从数组或切片生成新的切片:修改切片会更改原数组
var arr3 = [5]int{1, 2, 3, 4, 5}
fmt.Println("arr3:", arr3)
arr4 := arr3[1:3]
fmt.Println("arr4", arr4)
arr4 = append(arr4, 12)
fmt.Println("arr4", arr4)
fmt.Println("arr3:", arr3)
arr3: [1 2 3 4 5]
arr4 [2 3]
arr4 [2 3 12]
arr3: [1 2 3 12 5]
直接声明新的切片
// 声明字符串切片
var strList []string
使用make()函数构造切片
make( []Type, size, cap )
a := make([]int, 2)
b := make([]int, 2, 10)
fmt.Println(a, b)
fmt.Println(len(a), len(b))
[0 0] [0 0]
2 2
注意:Go 中函数传参仅有值传递一种方式;
func main() {
arr := [5]int{1, 3, 5, 6, 7}
fmt.Printf("addr:%p\n", &arr)// addr:0xc42001a1e0
s1 := arr[:]
fmt.Printf("addr:%p\n", &s1)// addr:0xc42000a060
changeSlice(s1)
}
func changeSlice(s []int) {
fmt.Printf("addr:%p\n", &s)// addr:0xc42000a080
fmt.Printf("addr:%p\n", &s[0])// addr:0xc42001a1e0
}
代码中定义了一个数组 arr,然后用它生成了一个slice。如果go中存在引用传递,形参 s 的地址应该与实参 s1 一样(上面c++的证明),通过实际的情况我们发现它们具备完全不同的地址,也就是传参依然发生了拷贝——值传递。
但是这里有个奇怪的现象,大家看到了 arr 的地址与 s[0] 有相同的地址,这也就是为什么我们在函数内部能够修改 slice 的原因,因为当它作为参数传入函数时,虽然 slice 本身是值拷贝,但是它内部引用了对应数组的结构,因此 s[0] 就是 arr[0] 的引用,这也就是能够进行修改的原因。
map的基本使用
make(map[KeyType]ValueType, [cap])
scoreMap := make(map[string]int, 8)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
fmt.Println(scoreMap)
fmt.Println(scoreMap["小明"])
fmt.Printf("type of a:%T\n", scoreMap)
fmt.Println()
userInfo := map[string]string{
"username": "pprof.cn",
"password": "123456",
}
fmt.Println(userInfo)
map[小明:100 张三:90]
100
type of a:map[string]int
map[password:123456 username:pprof.cn]
判断key是否存在
v, ok := scoreMap["张三"]
if ok {
fmt.Println(v)
} else {
fmt.Println("查无此人")
}
Go语言中使用for range遍历map。
scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["王五"] = 60
for k, v := range scoreMap {
fmt.Println(k, v)
}
使用delete()函数删除键值对
delete(map, key)
结构体
type person struct {
name string
city string
age int8
}
func main() {
var p1 person
p1.name = "pprof.cn"
p1.city = "北京"
p1.age = 18
fmt.Printf("p1=%v\n", p1) //p1={pprof.cn 北京 18}
fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"pprof.cn", city:"北京", age:18}
}
匿名结构体:定义一些临时数据结构等场景下还可以使用匿名结构体。
func main() {
var user struct{Name string; Age int}
user.Name = "pprof.cn"
user.Age = 18
fmt.Printf("%#v\n", user)
}
创建指针类型结构体
var p2 = new(person)
p2.name = "测试"
p2.age = 18
p2.city = "北京"
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:"测试", city:"北京", age:18}
取结构体的地址实例化
使用&对结构体进行取地址操作相当于对该结构体类型进行了一次new实例化操作。
p3 := &person{}
fmt.Printf("%T\n", p3) //*main.person
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"", city:"", age:0}
p3.name = "博客"
p3.age = 30
p3.city = "成都"
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"博客", city:"成都", age:30}
结构体初始化
type person struct {
name string
city string
age int8
}
func main() {
var p4 person
fmt.Printf("p4=%#v\n", p4) //p4=main.person{name:"", city:"", age:0}
}
使用键值对初始化
p5 := person{
name: "pprof.cn",
city: "北京",
age: 18,
}
fmt.Printf("p5=%#v\n", p5) //p5=main.person{name:"pprof.cn", city:"北京", age:18}
p6 := &person{
name: "pprof.cn",
city: "北京",
age: 18,
}
fmt.Printf("p6=%#v\n", p6) //p6=&main.person{name:"pprof.cn", city:"北京", age:18}
使用值的列表初始化
p8 := &person{
"pprof.cn",
"北京",
18,
}
fmt.Printf("p8=%#v\n", p8) //p8=&main.person{name:"pprof.cn", city:"北京", age:18}
1.必须初始化结构体的所有字段。
2.初始值的填充顺序必须与字段在结构体中的声明顺序一致。
3.该方式不能和键值初始化方式混用。
结构体定义并初始化
d := struct {
fn func() string
}{
fn: func() string { return "Hello, World!" },
}