Golang基础-7

本文详细介绍了Go语言中的函数概念、定义、调用方式,包括函数形参、返回值、递归函数、匿名函数和闭包的使用。重点展示了如何在Go程序中创建和利用这些功能,以及它们在代码复用和控制流程中的作用。
摘要由CSDN通过智能技术生成

Go语言基础

介绍

基础

介绍

  • 本文介绍Go语言中函数(函数定义、函数调用、函数形参、函数返回值、递归函数、匿名函数与闭包)等相关知识。

基础

函数
  • 函数是对代码片段的逻辑封装的集合。函数的作用就是提供代码复用性。
  • 函数之间属于并列关系,main 函数是程序执行的入口,且程序中只能有一个 main 函数。
  • 函数名称必须遵守Go语言命名规范,首字母大写表示对其它包可见,首字母小写表示只对本包可见。
  • 函数不支持函数重载,所以同一个包中的函数名必须不相同。
函数定义
  • 函数包含函数名、形参列表、函数体和返回值列表,使用关键字 func 声明,基本语法如下:

func 函数名称 (形参列表) (返回值列表) {
函数体
return + 返回值列表
}

package main

import "fmt"

// 无形参、无返回值
func main() {
	print(10, 20)
	fmt.Printf("a + b = %v\n", sum(10, 20))
}

// 有形参、无返回值
func print(a, b int) {
	fmt.Printf("a = %v, b = %v\n", a, b)
}

// 有形参、有返回值
func sum(a, b int) int {
	return a + b
}
函数调用
  • 函数之间属于并列关系,不允许在一个函数中定义另一个函数,可以在一个函数中调用另一个函数。
package main

import "fmt"

func main() { // main 函数中调用其它函数
	empty()                                 // 调用无参、无返回值函数
	print(10, 20)                           // 调用有参、无返回值函数
	fmt.Printf("a + b = %v\n", sum(10, 20)) // 调用有参、有返回值函数
	sum(20, 30)                             // 忽略函数返回值
}

func empty() { // 无形参、无返回值
	fmt.Println("empty")
}

func print(a, b int) { // 有形参、无返回值
	fmt.Printf("a = %v, b = %v\n", a, b)
}

func sum(a, b int) int { // 有形参、有返回值
	return a + b
}

输出结果
empty
a = 10, b = 20
a + b = 30

函数形参
  • 形参列表可以是 0 到 多个形参。函数形参支持可变参数,将可变参当作切片处理。可变参数只能定义一个,且只能在形参列表末端
package main

import "fmt"

func main() {
	test(10, 20, 30, 40, 50)

	// 将切片解包传递给函数形参
	test([]int{30, 40, 50}...)

	s := []int{30, 40, 50}
	test(s...)
	test(s[:1]...)
}

func test(args ...int) { // 可变参函数,将可变参数初始化为切片处理
	for i, v := range args {
		fmt.Printf("args[%v] = %v\t", i, v)
	}
	fmt.Println()
}

输出结果
args[0] = 10 args[1] = 20 args[2] = 30 args[3] = 40 args[4] = 50
args[0] = 30 args[1] = 40 args[2] = 50
args[0] = 30 args[1] = 40 args[2] = 50
args[0] = 30

  • 基本数据类型和数组是值传递,将实际参数拷贝一份到函数内部使用。若不想值传递,函数形参使用指针类型。
package main

import "fmt"

func main() {
	var a int = 10
	var b int = 20
	fmt.Printf("swap before: a = %v, b = %v\n", a, b)
	swap(a, b)
	fmt.Printf("swap after: a = %v, b = %v\n", a, b)
	fmt.Println("====================================")
	fmt.Printf("swap before: a = %v, b = %v\n", a, b)
	swap2(&a, &b)
	fmt.Printf("swap after: a = %v, b = %v\n", a, b)
}

func swap(a int, b int) { // 基本数据类型,将实参拷贝一份
	a, b = b, a
	fmt.Printf("swap: a = %v, b = %v\n", a, b)
}

func swap2(a *int, b *int) { // 通过指针实现两值交换,指针指向实参内存位置
	*a, *b = *b, *a
	fmt.Printf("swap ptr: a = %v, b = %v\n", *a, *b)
}

输出结果
swap before: a = 10, b = 20
swap: a = 20, b = 10
swap after: a = 10, b = 20
====================================
swap before: a = 10, b = 20
swap ptr: a = 20, b = 10
swap after: a = 20, b = 10

  • 形参列表中,对连续相同的类型可以对类型进行合并。
package main

import "fmt"

func main() {
	test(1, 2)
	test2(1, 2)
}

func test(a int, b int) { // 未合并形参类型
	fmt.Printf("test: a = %v, b = %v\n", a, b)
}

func test2(a, b int) { // 连续相同的形参变量类型进行合并
	fmt.Printf("test2: a = %v, b = %v\n", a, b)
}

输出结果
test: a = 1, b = 2
test2: a = 1, b = 2

函数返回值
  • 返回值类型列表数量可以存在 0 到多个返回值。
package main

import "fmt"

func main() {
	test()
	fmt.Println("test1: ", test1())

	a, b, c := test2()
	fmt.Printf("test2: %v, %v, %v\n", a, b, c)
}

func test() { // 无返回值
	fmt.Println("no return")
}

func test1() int { // 有一个返回值
	return 10
}

func test2() (int, int, int) { // 有多个返回值
	return 10, 20, 30
}

输出结果
no return
test1: 10
test2: 10, 20, 30

  • 函数返回值可以命名,函数内部通过此变量名给返回值赋值。
package main

import "fmt"

func main() {
	fmt.Println("test1: ", test1())

	a, b, c := test2()
	fmt.Printf("test2: %v, %v, %v\n", a, b, c)

	d, e, f := test3()
	fmt.Printf("test3: %v, %v, %v\n", d, e, f)
}

func test1() (r int) { // 有一个返回值
	r = 10
	return
}

func test2() (r1, r2, r3 int) { // 有多个返回值
	r1 = 10
	r2 = 20
	r3 = 30
	return
}

func test3() (r1 int, r2 int, r3 int) { // 有多个返回值
	r1 = 10
	r2 = 20
	r3 = 30
	return
}

输出结果
test1: 10
test2: 10, 20, 30
test3: 10, 20, 30

  • 函数也可以作为一种数据类型,可存储在容器中,也可作为函数参数传入或作为函数返回值。
package main

import "fmt"

func main() {
	// 函数类型变量
	var f func() int = test1
	fmt.Printf("a type: %T\n", f)
	f()

	// 函数类型作为形参
	fmt.Println("test2: ", test2(test1))

	// 函数类型作为返回值
	fmt.Println("test3: ", test3()())
}

func test1() (r int) { // 有一个返回值
	r = 10
	return
}

func test2(f func() int) (r int) { // 有一个返回值
	r = f()
	return
}

func test3() (f func() int) { // 有一个返回值
	f = test1
	return
}

输出结果
a type: func() int
test2: 10
test3: 10

递归函数
  • 递归函数是指在函数内部继续调用自己的函数。
  • 编写递归函数时必须要有终止条件,否则会无限次调用,内存溢出。
package main

import "fmt"

func main() {
	// 打印斐波那契数列
	for i := 1; i < 10; i++ {
		fmt.Print(fibonacci(i), ", ")
	}
	fmt.Println()

	// 打印阶乘
	for i := 1; i < 10; i++ {
		fmt.Print(factorial(uint32(i)), ", ")
	}
	fmt.Println()

}

// 计算斐波那契数列,n < 3时值为1,n > 2时,数值为前两个位置数值之和
func fibonacci(n int) (ret int) {
	if n < 3 {
		ret = 1
		return
	}

	ret = fibonacci(n-1) + fibonacci(n-2)
	return
}

// 计算正整数的阶乘(所有小于等于该数的正整数的积),0 的阶乘为 1
// n!=1×2×3×…×n
func factorial(n uint32) (ret uint32) {
	if n < 2 {
		ret = 1
		return
	}

	ret = n * factorial(n-1)
	return
}

输出结果
1, 1, 2, 3, 5, 8, 13, 21, 34,
1, 2, 6, 24, 120, 720, 5040, 40320, 362880,

匿名函数与闭包
  • 未指定函数名称的函数称之为匿名函数
  • 可以在局部代码块中使用、也可以作为其它函数的形参类型
package main

import "fmt"

func main() {
	// 定义匿名函数赋值给一个变量,通过变量调用匿名函数
	print := func() {
		fmt.Println("function 1")
	}

	print()

	// 定义匿名函数并调用
	func() {
		fmt.Println("function 2")
	}()

	// 调用形参传递匿名函数
	test(func() {
		fmt.Println("function 3")
	})
}

// 匿名函数作为函数形参
func test(print func()) {
	print()
}

输出结果
function 1
function 2
function 3

  • 匿名函数又可以称为闭包,在函数内部可以定义匿名函数,此匿名函数可以引用外部函数的变量。
  • 只要使用外部函数变量,其匿名函数生命周期一直存在,不会被自动销毁。
package main

import "fmt"

func main() {
	test()
}

// 定义闭包函数,以引用方式访问外部变量
func test() {
	var a int = 10
	func() {
		fmt.Printf("func() a = %v\n", a)
		a = 20
	}()
	fmt.Printf("test() a = %v\n", a)

	fmt.Println("test2(): ", test2("Hello")(" World!"))
}

// 函数内部定义闭包函数作为返回值
func test2(a string) func(string) string { // 返回值为匿名函数
	return func(b string) string {
		return a + b
	}
}

输出结果
func() a = 10
test() a = 20
test2(): Hello World!

起始

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值