数组切片
数组 - 定长序列,声明时需要指定长度:
<code class="language-go">var arr [5]int
arr[0] = 1
arr[1] = 2
fmt.Println(arr)
// [1 2 0 0 0]
arr2 := [5]int{1, 2, 3, 4, 5}
fmt.Println(arr2)
</code>
切片 - 引用数组的可变长度片段:
<code class="language-go">slice := arr[1:3] // 创建切片
slice = append(slice, 4) // 追加元素
fmt.Println(slice) //[2 0 4]
// 切片使用len()获取长度,cap()获取容量。
fmt.Println(len(slice), cap(slice)) // 3 4
</code>
for循环
<code class="language-go">// for循环遍历数组或切片:
for i := 0; i < len(slice); i++ {
fmt.Println(slice[i])
}
// 2
// 0
// 4
// for range遍历数组或切片:
for i, v := range arr {
println(i, v)
}
// 0 1
// 1 2
// 2 0
// 3 4
// 4 0
</code>
其中range关键字可以遍历数组/切片,返回索引和值。
切片比数组更常用,可以灵活添加元素。我们通常用for range循环来遍历切片
流程控制
条件判断 - if语句:
<code class="language-go">x := 10
if x > 10 {
fmt.Println("x is greater than 10")
} else {
fmt.Println("x is less than 10")
}
</code>
多条件判断 - switch语句:
<code class="language-go">operatingSystem := "linux"
switch operatingSystem {
case "darwin":
fmt.Println("Mac OS")
case "linux":
fmt.Println("Linux")
default:
fmt.Println("Other System")
}
</code>
循环语句 - for循环:
<code class="language-go"> for i := 0; i < 5; i++ {
fmt.Println(i)
}
</code>
循环控制语句:
continue:跳过当前循环,开始下一次循环
break:完全终止循环
goto:直接跳转到标签
defer语句 - 延迟调用:
<code class="language-go">defer fmt.Println("defer statement")
</code>
函数的使用
定义函数
<code class="language-go">func functionName(input1 type1, input2 type2) (output1 type1, output2 type2) {
// 函数体代码
return value1, value2
}
</code>
函数参数:
可以有多个输入参数,按类型声明
可以有多个返回值,或无返回值
调用函数
<code class="language-go">result1, result2 := functionName(param1, param2)
</code>
匿名函数
<code class="language-go">func(paramType) returnType {
// ...
}
</code>
闭包函数
<code class="language-go">func outer() func() {
x := 10
return func() {
fmt.Println(x)
}
}
</code>
Go语言函数支持多参数、多返回值、匿名函数和闭包等特性,用法灵活。可以实现一类通用逻辑,提高代码复用性。
简单的算法程序
<code class="language-go">package main
import "fmt"
func AvgNum(nums ...int) int{
var total int
for _, num := range nums{
total += num
}
return total / len(nums)
}
func AvgNum2(nums []int) int{
var total int
for _, num := range nums{
total += num
}
return total / len(nums)
}
func main(){
fmt.Println(AvgNum(1,2,3,4,5,6,7,8,9,10))
fmt.Println(AvgNum2([]int{1,2,3,4,5,6,7,8,9,10}))
}
</code>
包管理
Go语言的包管理主要通过如下方式:
导入包
在代码顶部导入需要的包,如:
<code class="language-go">import "fmt"
import "os"
</code>
init()函数
包中的init()函数会在包加载时自动执行。
包作用域
函数名和变量名都是包级作用域,可以通过包名来访问。
包名约定
按照目录命名,同一个目录下的Go文件属于一个包。
包依赖管理
Go Modules来管理依赖版本,在Go 1.13+后是默认方式。
主要命令:
go mod init 初始化
go get 添加依赖
go mod tidy 整理依赖
go mod graph 查看依赖图
包的可见性
通过大写字母开头的导出名来控制对外可见性。
掌握了包的使用方法,可以组织代码结构,有效复用代码。
包的简单应用
好的,这里以编写一个数字计算的简单包为例:
-
在自己的工作区创建 calc 包目录:$GOPATH/src/calc
-
在该目录下创建calc.go文件:
<code class="language-go">package calc
func Add(a, b int) int {
return a + b
}
func Sub(a, b int) int {
return a - b
}
</code>
- 在同一目录创建calc_test.go测试文件:
<code class="language-go">package calc
import "testing"
func TestAdd(t *testing.T) {
if Add(1, 2) != 3 {
t.Error("Add failed")
}
}
</code>
- 其他程序可以通过导入这个包来使用:
<code class="language-go">import "calc"
calc.Add(1, 2)
</code>
- 也可以为包起别名:
<code class="language-go">import c "calc"
c.Add(1, 2)
</code>
以上演示了如何编写一个简单的包,包含函数、测试、导入使用等,可以作为练习包管理的示例。
structs和methods
<code class="language-go">package main
import "fmt"
// 定义一个User结构体
type User struct {
Id int
Name string
Age int
}
// 为User结构体定义方法
func (u User) ToString() string {
return fmt.Sprintf("User: %d %s %d", u.Id, u.Name, u.Age)
}
func main() {
// 创建User对象
user := User{Id: 1, Name: "张三", Age: 23}
// 调用method
fmt.Println(user.ToString())
}
</code>
输出:
User: 1 张三 23
这里定义了一个User结构体,包含了Id、Name和Age字段。
然后为User结构体定义了ToString方法,该方法可以输出用户信息。
在main函数中,我们创建了User对象user,然后就可以直接调用user.ToString()方法。
这样便实现了基于struct和method的面向对象编程。
指针
<code class="language-go">package main
import "fmt"
func main() {
var a int = 10
// 指针ptr指向a
var ptr *int = &a
// 通过指针读取a的值
fmt.Println(*ptr)
// 通过指针修改a的值
*ptr = 20
fmt.Println(a)
}
示例解读:
声明变量a,初始值为10
声明指针ptr,存储变量a的地址 &a
可以通过 deferencing *ptr 读取指针指向的变量值
通过指针ptr修改变量a的值为20
打印a输出20,说明指针ptr通过引用修改了a
指针是Go语言实现引用传递的基础。正确使用指针可以在函数间传递引用而不仅是拷贝值。
</code>
map
这里是一个Go语言中map使用的简单示例:
<code class="language-go">package main
import "fmt"
func main() {
// 创建map
ages := make(map[string]int)
// 添加键值对
ages["Alice"] = 25
ages["Bob"] = 30
// 读取数据
fmt.Println(ages["Alice"])
// 遍历map
for name, age := range ages {
fmt.Println(name, age)
}
// 判断某键是否存在
_, ok := ages["Charlie"]
if !ok {
fmt.Println("Charlie not found")
}
}
示例解读:
1. 使用make创建map,键是字符串,值是int
2. 通过 key=value 语法插入键值对
3. 通过 key 读取值,如果不存在则返回值类型的零值
4. 可以遍历map获取到所有的键值对
5. 用value, ok := map[key]判断key是否存在
map是Go语言内建的哈希表实现,可以通过键快速查找值,非常实用。
</code>
为什么要使用匿名变量
在Go语言中,使用 _ 下划线声明的变量为匿名变量,通常用于忽略不需要的返回值。
在判断map中键是否存在的示例代码中:
<code class="language-go">_, ok := ages["Charlie"]
</code>
map在访问一个键时会返回两个值,第一个值是该键对应的值,第二个值是一个布尔值,表示该键是否存在。
这里我们不需要访问的值,只需要知道该键是否存在。所以使用 _ 忽略了第一个返回值,只获取了第二个返回值ok,来判断键是否存在。
如果写成:
<code class="language-go">value, ok := ages["Charlie"]
</code>
那么value会获取到值类型的零值。我们不需要value变量,所以使用匿名变量_忽略第一个返回值,这样代码更简洁。
所以Go语言中的匿名变量_ 主要用于丢弃不需要的返回值,从而简化代码。