数组
Go语言中的数组是固定长度的数据结构,其中的元素类型必须相同。数组的长度是数组类型的一部分,意味着不同长度的数组是不同类型。
Go语言的数组有一些内置的性能优势,但它们的大小必须在编译时确定,不能动态变化。
下面是一个数组的例子:
package main
import "fmt"
func main() {
// 1. 声明一个数组并初始化
var arr [5]int // 声明一个包含5个整数的数组,元素默认值为 0
arr[0] = 10 // 给元素赋值
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50
fmt.Println("Array:", arr) // 输出数组
// 2. 声明并初始化数组
arr2 := [3]string{"apple", "banana", "cherry"} // 声明一个包含3个字符串的数组并初始化
fmt.Println("Array2:", arr2) // 输出: [apple banana cherry]
// 3. 获取数组的长度
fmt.Println("Length of arr:", len(arr)) // 输出: 5
fmt.Println("Length of arr2:", len(arr2)) // 输出: 3
// 4. 遍历数组
fmt.Println("Iterating over arr:")
for i, v := range arr {
fmt.Printf("Index: %d, Value: %d\n", i, v)
}
fmt.Println("Iterating over arr2:")
for i, v := range arr2 {
fmt.Printf("Index: %d, Value: %s\n", i, v)
}
// 5. 多维数组
arr3 := [2][3]int{{1, 2, 3}, {4, 5, 6}} // 声明一个 2x3 的二维数组
fmt.Println("2D Array arr3:", arr3)
// 遍历二维数组
for i := 0; i < len(arr3); i++ {
for j := 0; j < len(arr3[i]); j++ {
fmt.Printf("arr3[%d][%d] = %d\n", i, j, arr3[i][j])
}
}
}
var arr [5]int 声明了一个包含 5 个整数的数组,数组的默认值为零值(对于整数类型是 0)。
arr2 := [3]string{"apple", "banana", "cherry"} 声明并初始化一个包含 3 个字符串元素的数组。
len() 函数可以返回数组的长度。
使用 for 循环和 range 关键字可以遍历数组元素。range 返回数组的索引和值。
arr3 := [2][3]int{{1, 2, 3}, {4, 5, 6}} 声明了一个 2 行 3 列的二维数组。可以通过嵌套的 for 循环遍历每一个元素。
数组在Go中是固定大小的,不能改变大小;数组有一些自带的方法,如使用len()可以获取数组的长度;Go也支持多维数组,可以用于存储矩阵等结构。
切片
Go 语言中的切片(slice)是一种底层数组的封装,提供了动态长度数组的功能,是 Go 中更常用的集合类型。下面是一个切片的示例。
package main
import "fmt"
func main() {
// 1. 创建一个切片
slice1 := []int{1, 2, 3, 4, 5} // 使用字面量创建一个切片
fmt.Println("slice1:", slice1)
// 2. 切片的长度和容量
fmt.Println("Length of slice1:", len(slice1)) // 输出切片的长度
fmt.Println("Capacity of slice1:", cap(slice1)) // 输出切片的容量
// 3. 使用 make 函数创建切片
slice2 := make([]int, 5) // 创建一个长度为5的切片,所有元素的初始值为零
fmt.Println("slice2:", slice2)
fmt.Println("Length of slice2:", len(slice2))
fmt.Println("Capacity of slice2:", cap(slice2))
// 4. 修改切片中的元素
slice1[2] = 100 // 修改切片中的第3个元素
fmt.Println("Modified slice1:", slice1)
// 5. 切片的扩展 (切片可以通过 append 函数扩展)
slice1 = append(slice1, 6, 7, 8) // 将 6, 7, 8 添加到 slice1 的末尾
fmt.Println("slice1 after append:", slice1)
// 6. 切片的截取
slice3 := slice1[1:4] // 从索引 1 到索引 3(不包括索引 4)截取切片
fmt.Println("slice3 (sliced from slice1):", slice3)
// 7. 遍历切片
fmt.Println("Iterating over slice1:")
for i, v := range slice1 {
fmt.Printf("Index: %d, Value: %d\n", i, v)
}
// 8. 多维切片
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
fmt.Println("Matrix (2D slice):", matrix)
// 遍历二维切片
for i, row := range matrix {
for j, value := range row {
fmt.Printf("matrix[%d][%d] = %d\n", i, j, value)
}
}
}
slice1 := []int{1, 2, 3, 4, 5}:使用字面量创建一个包含 5 个整数的切片。
slice2 := make([]int, 5):使用 make()函数创建一个长度为 5 的切片,所有元素默认值为 0。
len(slice)方法可以获取切片的长度,即当前包含的元素个数。
cap(slice)方法可以获取切片的容量,即底层数组的大小。
索引可以用来定位元素(像C语言一样),比如 slice1[2] = 100 将 slice1 中的第 3 个元素修改为 100。
append(slice, values...) 可以向切片添加元素,切片的长度会自动增加。
使用slice[start:end] 可以从切片中截取一部分。这里 slice1[1:4] 表示从索引 1 到索引 3(不包括索引 4)。
range关键字可以用来遍历切片的索引和值。
二维数组需要用类似matrix := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} 的语法来创建(有些像Java语法),另外也可以用嵌套的for循环遍历每个元素。
切片在Go中非常灵活,可以动态地增减元素,使用方便。可以使用make创建一个指定长度的切片,也可以直接通过字面量来初始化切片。切片具有动态大小,可以通过append函数扩展。另外切片可以通过截取操作来创建子切片,支持多维切片。
map
在 Go 语言中,map 是一种用于存储键值对的数据结构。它类似于其他编程语言中的字典或哈希表。map 可以快速查找、插入和删除元素。下面是一个 Go 语言中 map 使用的示例:
package main
import "fmt"
func main() {
// 1. 创建一个 map
studentScores := make(map[string]int)
// 2. 向 map 中添加元素
studentScores["Alice"] = 90
studentScores["Bob"] = 80
studentScores["Charlie"] = 95
// 3. 输出整个 map
fmt.Println("Student Scores:", studentScores)
// 4. 查找 map 中的值
score, exists := studentScores["Bob"]
if exists {
fmt.Println("Bob's score:", score)
} else {
fmt.Println("Bob's score not found.")
}
// 5. 修改 map 中的值
studentScores["Alice"] = 92
fmt.Println("Updated Student Scores:", studentScores)
// 6. 删除 map 中的元素
delete(studentScores, "Charlie")
fmt.Println("Student Scores after deletion:", studentScores)
// 7. 遍历 map
fmt.Println("Iterating over Student Scores:")
for name, score := range studentScores {
fmt.Printf("%s: %d\n", name, score)
}
// 8. 判断 map 是否为空
if len(studentScores) == 0 {
fmt.Println("The map is empty.")
} else {
fmt.Println("The map is not empty.")
}
}
使用 make(map[string]int) 创建一个空的 map,其中 string 表示键的类型,int 表示值的类型。
studentScores["Alice"] = 90 通过键 "Alice" 添加元素,将其分数设置为 90。
可以使用score, exists := studentScores["Bob"]这样的语法来查找数据,如果键存在,exists 将为 true,否则为 false。
map支持通过K-V键值对方式访问并直接赋值修改 map 中已有的元素,上面studentScores["Alice"] = 92 修改了 Alice 的分数。
使用 delete(studentScores, "Charlie") 删除键 "Charlie" 对应的元素。
使用 range 循环来遍历 map 中的所有键值对。在每一次循环中,name 是键,score 是值。
通过 len(studentScores) 可以检查 map 的长度,如果为 0,则说明 map 是空的。
另外,Go语言是没有自带的Set集合的。虽然可以用map来模拟set,但是会有一些内存浪费,这里可以自己用结构体实现一个。
函数
go的函数和其它不太一样,返回值是放在最后面的,而参数类型也是放在参数名后面。这样说有些抽象,直接看代码:
func add(a int, b int) int {
return a + b
}
这里a int 表示一个类型为int的变量a;最后的int表示函数的返回值。
另外go也支持返回多个值。此外如果入参都是一样的类型,可以只在最后标注一个类型。
func swap(a, b int) (int, int) {
return b, a // 返回两个整数,顺序颠倒
}
Go 允许定义匿名函数(没有名字的函数),并且可以在定义时立即执行。这里和Js类似,函数的参数就是函数体花括号后面圆括号内的值。
package main
import "fmt"
func main() {
// 定义并立即执行匿名函数
result := func(a, b int) int {
return a + b
}(3, 5)
fmt.Println("Sum from anonymous function:", result)
}
最后,作为支持函数式编程的语言,Go也支持将函数作为参数传递。
// 定义一个接受函数作为参数的函数
func applyOperation(a, b int, operation func(int, int) int) int {
return operation(a, b)
}
func main() {
// 定义加法操作
add := func(a, b int) int {
return a + b
}
result := applyOperation(5, 3, add) // 将匿名函数传递给 applyOperation
fmt.Println("Result of addition:", result)
}
Go也支持函数作为返回值,用来实现闭包(closure)等功能,这里不多赘述了。
另外,上面提到过Go语言也有指针类型,主要就是用来让函数修改调用方变量用的。这个功能在Java中被废除了,在Go中又被加入了回来。
面向对象
结构体
结构体作为面向对象系统的基石,在Go语言中当然也是存在的。
// 定义一个结构体
type Person struct {
Name string
Age int
}
func main() {
// 创建一个结构体实例
p := Person{
Name: "John",
Age: 30,
}
// 访问结构体字段
fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
}
这里出现了指针的第二个用途,可以用指针进行引用传递而非值拷贝。
截至目前这一步都还只是将结构体作为变量使用而已,接下来要引入面向对象:在结构体里引入方法。
Go的类方法不太一样,不是直接写在类里的,而是在函数func关键字后函数名前加上结构体名字。
type Rectangle struct {
Width float64
Height float64
}
// 定义一个方法,计算矩形的面积
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// 定义一个方法,修改矩形的宽度
func (r *Rectangle) SetWidth(w float64) {
r.Width = w
}
func main() {
// 创建一个结构体实例
rect := Rectangle{Width: 10, Height: 5}
// 调用方法
fmt.Println("Area of rectangle:", rect.Area())
// 修改矩形的宽度
rect.SetWidth(15)
fmt.Println("Updated area of rectangle:", rect.Area())
}
在使用时还是一样的,使用rect.SetWidth()这样的消息传递方法来调用方法。