Go语言基础第二弹——函数 | 青训营

105 阅读4分钟

1.匿名函数

在 Go 编程语言中,匿名函数是一种没有函数名的函数。它们通常被用作函数字面值(Function Literals)或闭包(Closures),以便在需要的地方直接定义和使用函数。

创建一个匿名函数的语法如下:

func() {
    // 函数体
}

匿名函数的一个重要特性是能够访问其外部作用域中的变量。这种行为称为闭包。下面是一个使用闭包的示例:

package main

import "fmt"

func main() {
   x := 5
   func() {
      x = 6
      fmt.Println(x) // 6
   }()
   fmt.Println(x) // 6
}

在 Go 中,闭包可以访问和修改其引用的变量。这意味着在闭包函数中修改变量的值会影响到原始变量,因为它们共享同一个内存地址。

2.defer/panic/recover

在 Go 编程语言中,deferpanicrecover是被用来处理错误和异常的三个关键字。

  • defer 用于延迟(defer)函数的执行,在当前函数返回之前进行执行。通过 defer 可以确保一些清理工作得到执行,比如关闭文件或释放资源。defer 语句会被添加到一个栈中,按照后进先出(LIFO)的顺序执行。
  • panic 用于引发(panic)一场。当某个不可恢复的错误发生时,可以使用 panic 引发异常。这个异常会导致程序的终止,但是在程序终止之前,panic 会沿着调用栈向上传递,直到被 recover 捕获或到达最顶层函数。
  • recover 用于从 panic 中恢复。通常情况下,recover 应该在 defer 函数中使用。它能够捕获 panic,并允许程序继续执行,避免程序终止。如果没有发生 panic 或者 panic 没有被捕获,recover 将返回 nil。
package main

import (
   "fmt"
)

func main() {
   defer func() {
      if r := recover(); r != nil {
         fmt.Println("Recovered:", r)
      }
   }()

   fmt.Println("Start")
   doSomething()
   fmt.Println("End")
}

func doSomething() {
   fmt.Println("Doing something...")
   panic("Oops, something went wrong!")
   fmt.Println("This line will never be executed")
}

在上面的示例中,当 doSomething 函数中的 panic 被触发时,程序会跳转到 main 函数的 defer 语句中的 recover()。然后程序继续执行,并输出 "Recovered: Oops, something went wrong!"。这样就成功地从 panic 中恢复,并继续执行程序。

请注意,panicrecover 应该被谨慎使用。通常情况下,应该只在无法处理的错误或者异常情况下使用 panicrecover,而不是作为常规的错误处理机制。

3.泛型函数

在Go语言中,泛型函数是一种可以处理多种数据类型的函数。它们可以接受不同类型的参数,并且可以在不同的上下文中使用。这使得我们能够编写更加灵活和通用的代码。

假设我们想编写一个函数,用于比较两个不同类型的值是否相等。我们可以使用泛型函数来实现这个功能,而不需要为每种类型都编写一个单独的函数。

下面是一个简单的泛型函数示例

func Equals[T comparable](a, b T) bool {
   return a == b
}

在这个例子中,我们使用了泛型类型参数T,它可以代表任意可比较的类型。函数的参数ab都是类型为T的值。函数内部的return a == b语句比较了这两个值是否相等,并返回一个布尔值。

使用这个泛型函数,我们可以比较不同类型的值,例如:

fmt.Println(Equals(5, 5))           // 输出: true
fmt.Println(Equals("hello", "world")) // 输出: false
fmt.Println(Equals(3.14, 3.14))     // 输出: true

Go语言中泛型函数的类型参数限定符:

  • comparable:表示该类型必须是可比较的,也就是说可以使用==!=进行比较。这个限定符适用于大多数基本类型和自定义类型,只要它们实现了相应的比较操作。
  • any:表示该类型可以是任意类型,没有任何限制。使用any作为类型参数可以接受任何类型的值,但在函数内部无法进行具体的类型操作。
  • numeric:表示该类型必须是数值类型,包括整数、浮点数和复数类型。
  • ordered:表示该类型必须是可排序的,也就是说可以使用<<=>>=进行比较。
  • slice:表示该类型必须是切片类型。
  • map:表示该类型必须是映射类型。
  • channel:表示该类型必须是通道类型。