复合数据类型
上一篇文章中我们学习了Go语言的基本数据类型,就和Java一样有8种基本数据类型一样,大致可以将这些基本数据类型分为整数型、浮点型、字符型、布尔型数据。接下来我们来学习Go语言的复合数据类型,以下是各种复合数据类型的特点和使用场景:
- 数组
- 特点:数组是一种固定长度、同一类型的数据结构,在声明时需要指定长度。
- 使用场景:适合用于存储具有固定数量的同类型数据,例如存储一组坐标、一组成绩等。
- 切片
- 特点:切片是一种引用类型的动态数组,它的长度可以随时改变,不需要在声明时指定长度。
- 使用场景:适合用于存储动态长度的同类型数据,例如存储日志、读取大文件、传输网络数据等。
- 映射
- 特点:映射是一种无序的键值对数据结构,在声明时无需指定长度,可以动态增删改查键值对。
- 使用场景:适合用于存储需要通过键值来访问的数据,例如存储字典、存储用户信息等。
- 结构体
- 特点:结构体是一种复合数据类型,可以将不同类型的数据组合在一起,形成一个自定义的数据类型,可以包含字段和方法。
- 使用场景:适合用于存储一组相关的数据,例如存储人的信息、存储车辆的信息等。
- 接口
- 特点:接口是一种抽象数据类型,定义了一个对象的行为,而不关心对象的具体类型,可以被不同的对象实现。
- 使用场景:适合用于实现多态性、接口隔离原则、依赖倒置原则等面向对象的编程概念,例如定义一个通用的排序函数,可以接受不同的数据类型并进行排序。
数组
// 定义一个长度为5的int类型数组
var arr [5]int
// 定义一个长度为5的int类型数组,并且赋初始值
//var arr = [5]int{1, 2, 3, 4, 5}
// 给数组的第三个元素赋值
arr[2] = 3
// 打印数组
fmt.Println("array:", arr)
// 打印数组长度
fmt.Println("array length: ", len(arr))
未赋值的下标处默认为0,和java是一样的
切片
切片其实的是对底层数组的封装,可以就看作是数组,但是他相对于数组优点是可以扩容,这里可以类比Java的ArrayList
// 定义一个空的切片
var slice []int
// 使用make函数初始化一个有3个元素的int类型切片
slice = make([]int, 3)
slice[0] = 1
slice[1] = 2
slice[2] = 3
fmt.Println("slice init: ", slice)
// 获取切片的长度和容量
var lenOfSlice int = len(slice)
var capOfSlice int = cap(slice)
fmt.Println("lenOfSlice init: ", lenOfSlice)
fmt.Println("capOfSlice init: ", capOfSlice)
// 添加元素到切片尾部
slice = append(slice, 4)
fmt.Println("slice append: ", slice)
// 获取切片的长度和容量
lenOfSlice = len(slice)
capOfSlice = cap(slice)
fmt.Println("lenOfSlice append: ", lenOfSlice)
fmt.Println("capOfSlice append", capOfSlice)
// 将切片从索引1开始到索引3的元素删除,然后,将索引的
/**
这段代码的意思是从 slice 中移除第 2 和第 3 个元素,然后将第 1 个元素和剩余的元素组成新的切片。
具体实现上,代码将 slice 切片中下标为 1 到 2(不包括第 2 个元素)的部分和下标为 3 开始到结尾的部分连接起来,
最后将结果重新赋值给 slice 变量。这个操作使用了可变参数函数 append 将两个切片连接起来。
*/
slice = append(slice[:1], slice[:3]...)
fmt.Println("slice remove: ", slice)
// 获取切片的长度和容量
lenOfSlice = len(slice)
capOfSlice = cap(slice)
fmt.Println("lenOfSlice remove: ", lenOfSlice)
fmt.Println("capOfSlice remove: ", capOfSlice)
// 切片迭代
for index, value := range slice {
fmt.Printf("index: %d,value: %d\n", index, value)
}
映射
映射是一种通过键值对存储数据,用途是根据key值快速查找到的对应的value,和Java中的HashMap很像,但是HashMap如果根据key值找不到value值会返回null值,而Go语言的映射会返回该Value值数据类型的默认值,例如value值的类型为int,那么如果根据key找不到数据时,会返回0
// 定义一个映射
var m map[string]int
m = make(map[string]int)
// 插入数据
m["apple"] = 1
m["banana"] = 2
m["orange"] = 3
// 查找数据
fmt.Println("apple:", m["apple"])
fmt.Println("banana:", m["banana"])
fmt.Println("orange:", m["orange"])
// 删除数据
delete(m, "banana")
fmt.Println("banana:", m["banana"])
// 判断数据是否存在
value, ok := m["banana"]
fmt.Println("banana exists:", ok, ",value: ", value)
// 遍历映射
for key, value := range m {
fmt.Println(key, ":", value)
}
结构体
结构体是一种自定义的数据类型,可以和Java的class类对比,它既有属性,也有方法。
// 定义一个结构体
type Person struct {
name string
age int
gender string
}
// 创建一个 Person结构体的实例
var p Person = Person{name: "jack", age: 20, gender: "male"}
// 访问结构体字段
fmt.Println("name: ", p.name)
fmt.Println("age: ", p.age)
fmt.Println("gender: ", p.gender)
// 修改结构体字段
p.age = 25
fmt.Println("age modiffied: ", p.age)
// 指针访问
var pp *Person = &p
// 通过指针访问和修改结构体字段
fmt.Println("Name (via pointer):", pp.name)
pp.name = "Jerry"
fmt.Println("Modified name (via pointer):", pp.name)
接口
接口的作用是定义一组方法,其实和Java的接口差不多,区别就是Go语言的接口中不能加静态属性
// 定义一个接口
type Animal interface {
speak() string
}
// 定义一个结构体
type Dog struct {
name string
}
// 实现Animal接口的方法
func (d Dog) speak() string {
return "汪汪汪"
}
// 定义另一个结构体
type Cat struct {
name string
}
// 实现Animal接口方法
func (c Cat) speak() string {
return "喵喵喵"
}
// 定义一个Aninal类型的变量
var animal Animal
// 将Dog类型的变量赋值给Animal类型的变量
animal = Dog{name: "小黄"}
// 调用Dog类型的speak方法,输出 '汪汪汪'
fmt.Println(animal.speak())
// 将Cat类型的变量赋值给Animal类型的变量
animal = Cat{name: "小白"}
// 调用speak方法,输出 "喵喵喵"
fmt.Println(animal.speak())