Go 语言入门指南:基础语法和常用特性解析(下)| 青训营

60 阅读7分钟

常用特性

函数

函数是一段封装了特定功能的代码,可以接收零个或多个参数,并返回零个或多个结果。在 Go 语言中,函数是一种一等公民,可以作为参数或返回值传递,也可以赋值给变量或作为结构体或接口的方法。

函数的定义使用关键字 func,后跟函数名、参数列表、返回值列表和函数体。例如:

func add(a int, b int) int { 
    return a + b // 返回 a 和 b 的和
}

func swap(a, b string) (string, string) {
    return b, a // 返回 a 和 b 的交换
}

func hello() { // 定义一个名为 hello 的函数,不接收任何参数,也不返回任何结果
    fmt.Println("Hello, world!") // 打印 "Hello, world!"
}

函数的调用使用函数名和实参列表,可以将返回值赋值给变量或直接使用。例如:

c := add(1, 2) // 调用 add 函数,传入 12 作为实参,将返回值赋值给变量 c
fmt.Println(c) // 打印 c 的值

d, e := swap("Go", "lang") // 调用 swap 函数,传入 "Go""lang" 作为实参,将返回值赋值给变量 d 和 e
fmt.Println(d, e) // 打印 d 和 e 的值

hello() // 调用 hello 函数,不传入任何实参,也不使用任何返回值

函数的参数可以是值传递引用传递,取决于参数的类型。值传递表示函数内部对参数的修改不会影响外部的变量,而引用传递表示函数内部对参数的修改会影响外部的变量。一般来说,基本类型和结构体类型是值传递,而切片、映射、通道、指针和接口类型是引用传递。

函数的返回值可以是命名返回值非命名返回值,取决于是否在返回值列表中指定了变量名。命名返回值表示函数内部可以直接使用返回值变量,并且可以使用 return 关键字省略返回值列表。非命名返回值表示函数内部需要显式地指定返回值列表。

函数的特性包括:

  • 可变参数:表示函数可以接收任意数量的同类型参数,使用 ... 表示可变参数。例如:
func sum(nums ...int) int { 
    total := 0 // 声明并初始化一个整型变量 total,并赋值为 0
    for _, num := range nums { // 使用 for-range 循环遍历 nums 中的每个元素
        total += num // 将 total 加上 num
    }
    return total // 返回 total
}

fmt.Println(sum(1, 2, 3)) // 调用 sum 函数,传入 1, 2, 3 作为实参,打印返回值
fmt.Println(sum(10, 20)) // 调用 sum 函数,传入 10, 20 作为实参,打印返回值
fmt.Println(sum()) // 调用 sum 函数,不传入任何实参,打印返回值
  • 匿名函数:表示没有名字的函数,可以在需要时定义和使用。匿名函数可以作为闭包(closure),捕获外部变量的值。例如:
func main() { 
    a := 10 // 声明并初始化一个整型变量 a,并赋值为 10
    f := func() { // 定义一个匿名函数,并赋值给变量 f
        fmt.Println(a) 
    }
    f() // 调用 f 函数
    a = 20 // 将 a 的值修改为 20
    f() 
}
  • 延迟执行:表示在函数返回前执行一些操作,使用关键字 defer 实现。延迟执行常用于清理或释放资源的操作。例如:
func main() { 
    file, err := os.Open("test.txt") // 打开一个名为 test.txt 的文件,并将文件对象和错误信息赋值给变量 file 和 err
    if err != nil { // 如果 err 不为空
        fmt.Println(err) // 打印 err 的内容
        return // 返回并结束程序
    }
    defer file.Close() // 使用 defer 关键字延迟执行 file.Close() 方法,在 main 函数返回前关闭文件

    data := make([]byte, 100) // 使用 make 函数创建一个长度为 100 的字节切片 data
    file.Read(data) // 使用 file.Read 方法读取文件内容到 data 中
    fmt.Println(string(data)) // 将 data 转换为字符串并打印
}

并发编程

并发编程是指让程序可以同时执行多个任务,提高程序的性能和响应速度。Go 语言提供了一套原生的并发编程机制,包括 goroutine 和 channel

  • goroutine:表示一种轻量级的线程,可以在一个进程中创建成千上万个,并且可以自动调度和切换。goroutine 的创建使用关键字 go,后跟一个函数或方法调用。例如:
func sayHello() {
    fmt.Println("Hello, world!") 
}

func main() { 
    go sayHello() // 使用 go 关键字创建一个 goroutine,并调用 sayHello 函数
    time.Sleep(time.Second) // 让主线程休眠一秒,等待 goroutine 执行完毕
}
  • channel:表示一种用于在不同 goroutine 之间传递数据的管道,可以实现同步或异步的通信。channel 的创建使用内置函数 make,并指定通道的元素类型。channel 的操作使用 <- 符号,表示发送或接收数据。例如:
func sum(nums []int, c chan int) { // 定义一个名为 sum 的函数,接收一个整型切片 nums 和一个整型通道 c 作为参数
    total := 0 // 声明并初始化一个整型变量 total,并赋值为 0
    for _, num := range nums { // 使用 for-range 循环遍历 nums 中的每个元素
        total += num // 将 total 加上 num
    }
    c <- total // 将 total 发送到通道 c 中
}

func main() {
    nums := []int{1, 2, 3, 4, 5} // 声明并初始化一个整型切片 nums,并赋值为 [1, 2, 3, 4, 5]
    c := make(chan int) // 使用 make 函数创建一个整型通道 c
    go sum(nums[:len(nums)/2], c) // 使用 go 关键字创建一个 goroutine,并调用 sum 函数,传入 nums 的前半部分和通道 c 作为参数
    go sum(nums[len(nums)/2:], c) // 使用 go 关键字创建另一个 goroutine,并调用 sum 函数,传入 nums 的后半部分和通道 c 作为参数
    x, y := <-c, <-c // 分别从通道 c 中接收两个数据,并赋值给变量 x 和 y
    fmt.Println(x, y, x + y) // 打印 x,y 和 x + y 的值
}

总结

Go 语言是一种开源的编程语言,由 Google 的 Robert Griesemer, Rob Pike 和 Ken Thompson 在 2007 年设计,并于 2009 年正式发布。Go 语言的设计目标是实现高效、可靠、简洁、易读和跨平台的软件开发。Go 语言的特点包括:

  • 静态类型:在编译时确定变量的类型,提高运行效率和安全性。
  • 自动垃圾回收:由运行时系统自动管理内存的分配和释放,简化编程的难度。
  • 并发编程:提供了原生的 goroutine 和 channel 机制,实现高效的多任务处理。
  • 函数式编程:支持函数作为一等公公民,闭包,匿名函数,多返回值,延迟执行等特性。
  • 面向接口编程:使用结构体和接口实现面向对象编程,避免了继承带来的复杂性和脆弱性。

Go 语言的基础语法包括:

  • 变量和常量:使用 var 和 const 关键字声明变量和常量,并可选地指定类型和初始值。
  • 数据类型:包括布尔类型,数值类型,字符串类型,数组类型,切片类型,映射类型,结构体类型,接口类型等。
  • 流程控制:包括条件语句,循环语句,选择语句,跳转语句等。
  • 函数:使用 func 关键字定义函数,并指定参数列表,返回值列表和函数体。

Go 语言的常用特性包括:

  • 可变参数:使用 ... 表示函数可以接收任意数量的同类型参数。
  • 匿名函数:表示没有名字的函数,可以在需要时定义和使用,并可以作为闭包捕获外部变量的值。
  • 延迟执行:使用 defer 关键字表示在函数返回前执行一些操作,常用于清理或释放资源的操作。
  • 并发编程:使用 go 关键字创建 goroutine,并使用 make 函数创建 channel,并使用 <- 符号发送或接收数据。