Go语言基本语法(四)函数与变量的作用域

发布于:2024-04-30 ⋅ 阅读:(23) ⋅ 点赞:(0)

函数

Go语言中的函数(Function)是执行特定任务的代码块,它们是构建程序的基本单位之一。函数可以接受输入参数,执行一系列操作,并可返回结果。Go语言的函数设计简洁,强调代码的清晰度和模块化。下面是Go函数的一些关键特征和一个示例说明:

Go函数的特征:

  1. 定义格式:函数以func关键字开始,后面跟着函数名、参数列表(如果有的话)、返回值列表(如果有的话),最后是函数体。

  2. 参数与返回值:函数可以有零个、一个或多个参数,以及零个、一个或多个返回值。参数和返回值的类型需明确指定。

  3. 多值返回:Go语言支持函数返回多个值,这是一个强大的特性,可以用来避免错误码或使用额外的输出参数。

  4. 匿名函数与闭包:Go语言支持匿名函数(也称作lambda函数)和闭包,它们可以捕获其定义时的上下文变量,提供灵活的编程能力。

  5. defer、panic与recover:Go提供了异常处理机制,通过defer来注册延迟执行的函数,panic用于抛出异常,recover则用于捕获并恢复从panic产生的异常流程。

示例说明:

下面是一个简单的Go函数示例,该函数接受两个整数作为参数,返回它们的和与差。

package main

import "fmt"

// 这是一个加减法函数,接受两个int类型的参数,返回两个int类型的值(和与差)
func calculateSumAndDifference(a, b int) (sum int, difference int) {
    sum = a + b
    difference = a - b
    return // 自动返回sum和difference
}

func main() {
    // 调用calculateSumAndDifference函数
    sum, diff := calculateSumAndDifference(10, 5)
    fmt.Printf("Sum: %d, Difference: %d\n", sum, diff) //输出Sum: 15, Difference: 5
}

形参与实参:

形参与实参是函数调用中两个重要的概念,它们描述了函数参数的两个方面:

形参(形式参数, Formal Arguments)

  • 定义:形参是在定义函数时,在函数签名的括号内声明的参数。它们是一组占位符,代表将来调用函数时将要传递的具体值的位置。形参在函数体内部使用,用于接收调用者提供的数据。
  • 特性
    • 形参仅在函数内部有效,其生命周期局限于函数执行期间。
    • 形参在函数未被调用时并不占用实际的存储空间,只有在函数调用发生时,根据实参分配相应的内存。
    • 形参的名称供函数内部使用,调用者不需要知道形参的名字。
// 函数定义
func addNumbers(x int, y int) int {
    sum := x + y
    return sum
}

在这个例子中:

  • x 和 y 是形参(形式参数)。它们是函数定义的一部分,用来指定函数需要接收什么样的数据输入。这里,x 和 y 都是整型(int)变量,代表将来调用此函数时用户需要提供的两个整数值的位置。

实参(实际参数, Actual Arguments)

  • 定义:实参是在调用函数时,实际传递给函数的具体值或变量。这些值或变量用来给形参赋值,使得函数能够使用这些数据进行操作。
  • 特性
    • 实参可以是常量、变量、表达式或其它函数的返回值。
    • 调用函数时,实参的值(或地址,对于指针或引用类型)被复制给对应的形参。
    • 实参在调用函数之前必须已经初始化,即具有确定的值。
    • 实参的生命周期独立于函数调用,它们可能在函数调用之前就已经存在,并且在函数调用结束后继续存在。
// 函数调用
result := addNumbers(3, 4)
fmt.Println(result) // 输出结果:7

在函数调用中:

  • 3 和 4 是实参(实际参数)。它们是调用函数时传递给函数的具体数值。在这里,我们将 3 赋给了形参 x,将 4 赋给了形参 y。函数内部,这些实参的值被用来执行计算,然后返回结果。

两者的关系

  • 匹配:在函数调用时,实参的数量、类型和顺序必须与形参一一对应,否则会导致编译错误。
  • 数据传递:调用函数时,实参的值(对于值类型)或引用(对于引用类型)被传递给形参。对于基本数据类型,这种传递是值传递,即形参接收到的是实参的一个副本;而对于指针或引用类型,则是引用传递,形参和实参共享同一份数据的地址。
  • 作用域:形参的作用域局限在函数内部,而实参的作用域则取决于它们在程序中的定义位置,可以是全局的,也可以是局部的。

匿名函数

匿名函数是没有名字的函数,它们可以直接在代码中定义并立即使用,通常作为值传递给其他函数或赋值给变量。匿名函数的语法简洁,形式如下:

add := func(a, b int) int {
    return a + b
}

在这个例子中,add变量被赋予了一个匿名函数,这个函数接受两个整数参数并返回它们的和。

闭包函数

闭包是Go语言中匿名函数的一个特例,它不仅包含了函数体,还携带了对其定义时周围变量(自由变量)的引用。这意味着闭包可以访问并修改在其外部作用域中定义的变量,即便这些变量在原始作用域之外已经不再存在。闭包使得函数能够“记住”它被创建时的环境。

闭包的一个典型应用场景是返回一个函数,这个返回的函数能继续访问并操作外部函数的局部变量:

func counter() func() int {
    count := 0 // 这是一个自由变量,被闭包捕获
    return func() int {
        count++
        return count
    }
}

increment := counter()
fmt.Println(increment()) // 输出:1
fmt.Println(increment()) // 输出:2

变量作用域

  1. 局部作用域

    • 在函数体内声明的变量被称为局部变量。它们仅在该函数内部可见,并且在函数执行结束后自动释放。
    • 块作用域:即使是函数内部更小的代码块(如if语句、for循环等内部),声明的变量也只能在该块及其嵌套的子块中访问。
    • 函数参数也是局部变量,它们的作用域限制在该函数内部。
package main

import "fmt"

func main() {
	// 这是一个局部变量
	var localVar int = 50
	fmt.Println("局部变量的值:", localVar) //局部变量的值: 50
	incrementLocalVar(localVar)
	// 注意:即使在incrementLocalVar内部修改了localVar的值,这里的值也不会改变
	fmt.Println("原局部变量的值(未改变):", localVar) //原局部变量的值(未改变): 50
}

func incrementLocalVar(num int) {
	num = num + 10
	fmt.Println("在函数内部修改后的局部变量的值:", num) //在函数内部修改后的局部变量的值: 60
}
  1. 全局作用域

    • 在函数外部定义的变量称为全局变量,它们在整个包内都是可见的。如果在同一个包的不同文件中要访问全局变量,需要使用import语句中的.操作符来导入该变量所在的文件(尽管通常不鼓励过度使用全局变量)。
    • 全局变量在整个程序生命周期内都存在,且初始化发生在程序启动时。
package main

import "fmt"

// 这是一个全局变量
var globalVar int = 100

func main() {
	fmt.Println("全局变量的值:", globalVar) //全局变量的值: 100
	modifyGlobalVar()
	fmt.Println("修改后的全局变量的值:", globalVar) //修改后的全局变量的值: 110
}

func modifyGlobalVar() {
	globalVar = globalVar + 10
}


网站公告

今日签到

点亮在社区的每一天
去签到