6.go语言函数

Go语言中的函数是组织代码的最小单元,用于封装一段代码,完成特定的功能。函数的使用可以减少代码冗余,提高代码的可读性和可维护性。

函数的基本定义和语法

在Go语言中,定义一个函数的基本语法如下:

func functionName(parameter1 type1, parameter2 type2, ...) (returnType, returnType...){

// 函数体 return value1,value2... // 返回值

}

  • func:关键字用于定义函数。

  • functionName:函数名,用于唯一标识该函数。

  • parameter1 type1, parameter2 type2, ...:参数列表,函数可以接收零个或多个参数。每个参数由参数名和参数类型组成,多个参数之间使用逗号分隔。

  • returnType:返回类型,指定函数的返回值的数据类型。可以返回零个或多个值

  • return value:返回值,如果有返回值,则需要使用return语句将结果返回给调用者。

如果没有返回值,可以不写 return。如果写了,代表退出整个函数。

命名返回值

go语言支持为返回值命名。这些命名的返回值可以在函数体内部直接使用,而不需要显式地返回它们。这种方式特别适用于在函数执行过程中逐步构建或计算返回值,或者在满足特定条件时提前返回。

复制代码
func sum(a, b int) (result int) {
         result = a + b // 直接赋值给命名返回值
      if result >= 0 {
          return // 提前返回,此时 result 自动返回
      }
      // 可以继续处理其他逻辑。比方返回值小于0,打印一句提醒,并把结果处理成正数。
      fmt.Println("您的计算结果小于0,已经为您取绝对值")
      result = result * -1
      return // 最终返回 result
}
 
func main() {
    fmt.Println(sum(5, 7))  // 输出: 12
    fmt.Println(sum(-3, -7)) // 输出: (您的计算结果小于0,已经为您取绝对值  10)
}

函数的调用方式

函数的调用是通过函数名加上括号实现的。如果函数有参数,调用时需要在括号内传入实际的参数值。例如:

复制代码
func add(a int, b int) int {
return a + b
}
func main() {
    result := add(3, 5) // 调用add函数,传入3和5作为参数
    fmt.Println("3 + 5 =", result) // 输出结果
}

定义多返回值函数

你可以在函数定义时,通过在参数列表后直接指定返回值的类型来实现多返回值。每个返回值类型之间用逗号分隔。

使用函数时候,你只对函数的某些返回值感兴趣,可以使用下划线(_)来忽略不需要的返回值。

复制代码
func divide(a, b int) (int, int) {
    r := a / b
    return r, a % b // 可以使用变量 返回,也可以使用表达式计算结果返回
}
 
func main() {
    _, remainder := divide(10, 3) // 只关心余数,忽略商数
    fmt.Println("Remainder:", remainder)
}

//注意,定义无返回值函数,不能使用变量接收 函数的返回。

可变参数

go语言,不支持给参数设置默认值。

但是支持,可变参数。使用...type 定义。把收集到多余的实参,存放到对应类型的切片中。

匿名函数

匿名函数是通过 func 关键字直接定义的,没有指定函数名。你可以将匿名函数赋值给一个变量,或者直接调用它。

复制代码
  myFunction := func(x, y int) int {
        return x + y
    }
     // 调用匿名函数
    result := myFunction(5, 10)
    fmt.Println(result) // 输出: 15
   
   // 直接调用匿名函数
    result := func(x, y int) int {
        return x + y
    }(5, 10)
    fmt.Println(result) // 输出: 15

go函数作为参数类型

函数作为参数的使用方式非常简单,我们只需要将需要传递的函数作为参数传递给另一个接受这个函数作为参数的函数即可。

如果逻辑代码很复杂,上边代码就很 臃肿,不容易让人理解。我们可以。把函数签名声明为一个类型。

函数闭包

闭包通常涉及到定义一个函数,该函数在其内部定义了另一个函数,并将该函数返回出去,返回出去的函数可以访问外部函数的变量。

复制代码
package main
 
import "fmt"
 
func outerFunction() func() int {
    var x = 10
    return func() int {
        x++
        return x
    }
}
 
func main() {
    myClosure := outerFunction() // 获取闭包
    fmt.Println(myClosure()) // 输出: 11
    fmt.Println(myClosure()) // 输出: 12
}

函数总结

函数的特性

Go语言的函数具有以下特性:

  • 支持不定参数:可以使用...来表示不定参数,允许函数接收任意数量的参数。

  • 支持多返回值:可以返回多个结果,例如错误信息和结果值。

  • 支持命名返回参数:可以在函数内部给返回值命名,方便处理返回值。

  • 支持匿名函数和闭包:可以定义匿名函数并在需要时调用。

  • 函数也是一种类型:一个函数可以赋值给变量,实现更灵活的调用。

  • 不支持嵌套、重载和默认参数:Go语言不支持在一个包中定义两个名字相同的函数、函数的重载以及默认参数

defer 延迟调用

defer的核心作用是延迟调用函数或方法,

这意味着defer语句所指定的函数调用会被推迟到当前函数返回之前执行,无论函数是正常返回还是因发生异常而返回。

当一个函数中有多个defer语句时,它们会按照后进先出的顺序执行。也就是说,最后一个defer语句所指定的函数会最先被调用,而第一个defer语句所指定的函数最后被调用。例如:

递归 是一种常见的编程技术,它允许函数直接或间接地调用自身。

递归的核心思想在于将一个大问题分解为若干个小问题,然后逐步解决这些小问题,最终达到解决整个大问题的目的。

特点:

自身调用:原问题可以分解为子问题,子问题和原问题的求解方法是一致的,即都是调用自身的同一个函数。

终止条件:递归必须有一个终止的条件,即不能无限循环地调用本身。

简洁但效率不高:递归算法解题通常显得很简洁,但递归算法解题的运行效率较低,因为数据存入堆栈中,等待函数调用结束后再取出,会增加性能消耗。另外堆栈还存在溢出的风险。

计算阶乘的递归函数:

func factorial(n uint) uint {

if n == 0 {

return 1 // 递归终止条件

}

return n * factorial(n-1) // 调用自身

}

  • . 构建递归调用堆栈

每次函数调用自身时,一个新的调用实例被推入调用堆栈。直到达到基本情况,才开始从堆栈中逐个返回结果。这个过程类似于函数调用链的构建和解析。

  • 避免无限递归和栈溢出

正确设置递归终止条件,确保每个递归函数都有清晰定义的基本情况是非常重要的,否则可能会导致无限递归,进而耗尽栈空间,导致程序崩溃(栈溢出)。

  • 优化递归(尾递归优化)

在某些情况下,可以通过尾递归优化来提高效率。尾递归是指在函数的最后一步调用自身的情况。Go语言在某些情况下可以优化尾递归,使其表现得像循环一样,从而避免栈溢出。

递归 是实现诸如树遍历、排序算法(如 快速排序 )、 斐波那契数列 ,图与树的遍历搜索 等多种算法的有效方式

快速排序的实现

复制代码
package main
 
import (
    "fmt"
)
 
// quickSort 对数组 arr 进行快速排序
func quickSort(arr []int) []int {
    if len(arr) < 2 {
        // 基本情况:数组只有一个元素或为空,无需排序
        return arr
    }
    left, right := 0, len(arr)-1
    // 选择最右边的元素作为基准值
    pivot := right
    // 将数组分为小于基准和大于基准的两部分
    newPivot := partition(arr, left, right, pivot)
    // 递归排序左右两部分
    quickSort(arr[:newPivot])
    quickSort(arr[newPivot+1:])
    return arr
}
 
// partition 对数组进行划分,返回新的基准位置
func partition(arr []int, left, right, pivot int) int {
    pivotValue := arr[pivot]
    // 将基准值交换到最右边,即最后一个位置
    arr[pivot], arr[right] = arr[right], arr[pivot]
    storeIndex := left
    for i := left; i < right; {
        if arr[i] < pivotValue {
            arr[i], arr[storeIndex] = arr[storeIndex], arr[i]
            storeIndex++
        }
        i++
    }
    // 将基准值放到正确的位置上
    arr[storeIndex], arr[right] = arr[right], arr[storeIndex]
    return storeIndex // 返回新的基准位置
}
 
func main() {
    arr := []int{10, 7, 8, 9, 1, 5}
    fmt.Println("Original array:", arr)
    sortedArr := quickSort(arr)
    fmt.Println("Sorted array:  ", sortedArr)
}

go内置排序函数

sort.Slice进行通用排序

从Go 1.8开始,sort包引入了Slice函数,它允许你直接对切片进行排序,而无需实现任何接口。

复制代码
package main
 
import (
    "fmt"
    "sort"
)
 
func main() {
    a := []int{3, 1, 4, 1, 5, 9}
    sort.Slice(a, func(i, j int) bool { return a[i] < a[j] }) // 使用闭包进行排序逻辑定义
    fmt.Println(a) // 输出: [1 1 3 4 5 9]
}
相关推荐
在下千玦7 分钟前
#前端js发异步请求的几种方式
开发语言·前端·javascript
Dante79812 分钟前
判断质数及其优化方法
开发语言·c++·算法
Bruce_Liuxiaowei25 分钟前
DeepSeek API集成开发指南——Flask示例实践
后端·python·flask·deepseek
ylfhpy31 分钟前
Java面试黄金宝典19
java·开发语言·数据结构·算法·面试·面经
易元37 分钟前
设计模式-享元模式
后端
码农幻想梦1 小时前
18491 岛屿的数量
android·java·开发语言
Angelyb1 小时前
前端Vue
开发语言·javascript·ecmascript
MobiCetus1 小时前
C++中的智能指针
开发语言·jvm·c++
白羊不吃白菜1 小时前
PAT乙级(1107 老鼠爱大米)C语言详解
c语言·开发语言
老友@1 小时前
从 Word 到 HTML:使用 Aspose.Words 轻松实现 Word 文档的高保真转换
java·后端·性能优化·html·word·aspose·格式转换