Go 基础 6 函数

6 函数

6.1 介绍

Go里面有三种类型的函数:

1.普通的带有名字的函数

2.匿名函数或lambda函数

3.方法(Methods)

除了main()、init()函数外,其他所有类型的函数都可以有参数与返回值。函数参数,返回值和它们的类型统称为函数签名。

注意:Go里面不允许函数重载(编写多个同名函数,它们拥有不同的形参或不同的返回值),会导致编译错误。不支持的原因是:函数重载需要进行多余的类型匹配影响性能。

函数也可以 以声明的形式被使用,作为一个函数类型

type f func(int,int) int
package main

import "fmt"
func add(a, b int) int {
	return a + b
}
//sub作为函数名可以看成是 op 类型的常量
func sub(a, b int) int {
	return a - b
//定义函数类型 op
type op func(a, b int) int
//形参指定传入参数为函数类型op
func Oper(fu op, a, b int) int {
	return fu(a, b)
}
func main() {
	//在go语言中函数名可以看做是函数类型的常量,所以我们可以直接将函数名作为参数传入的函数中。
	aa := Oper(add, 1, 2)
	fmt.Println(aa)
	bb := Oper(sub, 1, 2)
	fmt.Println(bb)
}

函数可以赋值给变量 例如func Oper(fu op,a ,b int) int。fu变量的类型是op,op是函数类型。

函数不能再其它函数里面声明,不过可以通过匿名函数实现。

6.2 函数参数与返回值

Go默认使用按值传递来传递参数,也就是传递参数的副本。函数接收参数副本之后,在使用变量的过程中可能对副本的值进行修改,但不会影响原来的变量。

如果想要函数可以直接修改参数的值,而不是对参数的副本进行操作,需要将参数的地址(变量名前面添加&)传递给函数,这就是按引用传递,此时传递给函数的是一个指针,指针的值(变量的内存地址)会被复制,但指针指向的变量不会被复制,通过地址来修改变量的值。几乎再所有情况下,传递指针的消耗都比传递副本来的少。

命名返回值和非命名返回值,return在函数中的使用

package main

import "fmt"

var num int = 10
var numx2, numx3 int

func main() {
    numx2, numx3 = getX2AndX3(num)
    PrintValues()
    numx2, numx3 = getX2AndX3_2(num)
    PrintValues()
}

func PrintValues() {
    fmt.Printf("num = %d, 2x num = %d, 3x num = %d\n", num, numx2, numx3)
}

//getX2AndX3函数只定义返回值的类型,没有定义返回值的名称 这就是非命名返回值
func getX2AndX3(input int) (int, int) {
    return 2 * input, 3 * input
}
//getX2AndX3_2函数 既定义了返回值类型也定义了返回值的名称 这是命名返回值
func getX2AndX3_2(input int) (x2 int, x3 int) {
    x2 = 2 * input
    x3 = 3 * input
    // return x2, x3 
    return
}

return和return var1,var2都可以。

即使函数使用了命名返回值,也可以无视它返回明确的值

不建议定义函数的返回值时 使用非命名返回值

6.2.1 空白符

空白符用来匹配一些不需要的值,然后丢弃掉。

package main

import "fmt"

func main() {
    var i1 int
    var f1 float32
    i1, _, f1 = ThreeValues()
    fmt.Printf("The int: %d, the float: %f \n", i1, f1)
}

func ThreeValues() (int, int, float32) {
    return 5, 6, 7.5
}
//The int: 5, the float: 7.500000
6.2.2改变外部变量
func main(){
    n := 0
	reply := &n
	loop12(10, 2, reply)
	fmt.Println("a * b = ", *reply)
}
func loop12(a, b int, reply *int) {
	*reply = a * b
}
//a * b =  20

6.3 传递变长参数

如果函数的最后一个参数是…type的形式,那么这个函数就可以处理一个变长的参数,这个长度可以是0,这样的函数称为变长函数。

func f(a,b, arg ...int) {}

例子1:

func Greeting(prefix string, who ...string)
Greeting("hello:", "Joe", "Anna", "Eileen")

在Greeting函数中,变量who的值为[]string{“Joe”, “Anna”, “Eileen”}

例子2

package main

import "fmt"

func main() {
	x := min(1, 3, 2, 5)
	fmt.Printf("min num : %d\n", x)
	slice := []int{1232, 543, 513, 865, 834, 34}
	x = min(slice...)
	fmt.Printf("The minimum in the slice is : %d\n", x)
}

func min(s ...int) int {
	if len(s) == 0 {
		return 0
	}
	min := s[0]
	for _, v := range s {
		if v < min {
			min = v
		}
	}
	return min
}
//min num : 1
//The minimum in the slice is : 34

如果参数被存储在一个slice类型的变量中,则可以通过slice…的形式来传递参数。

6.4 defer和追踪

使用关键字defer,指定某个语句在函数返回之前(执行return语句之后)才执行。

例子:在f1的函数体执行输出1和3之后 才执行f2函数

func main() {
	f1()
}
func f1() {
	fmt.Println(1)
	defer f2()
	fmt.Println(3)
}
func f2() {
	fmt.Println(2)
}
//1                               
//3                               
//2 

例子:调用f3() 会输出0

defer关键字标记了fmt.Println(i) 此时的i = 0

当f3()执行完return 后 再执行fmt.println(i)

func main() {
	f3()
}
func f3() {
	i := 0
	defer fmt.Println(i)
	i++
	return
}
//0

当一个函数体中需要执行多次defer标记的语句 它们会以逆序执行(先进后出)

func f4() {
	for i := 0; i < 5; i++ {
		defer fmt.Println(i)
	}
}
//4 
//3
//3
//1
//0

6.5 内置函数

Go语言有一些不需要进行导入操作就可以使用的内置函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TJEy5g21-1651279806225)(D:\markdown文件\go\photo\Snipaste_2022-04-25_15-57-56.png)]

6.6 递归函数

func main() {
	
	result := 0
	for i := 0; i <= 10; i++ {
		result = fibonacci(i)
		fmt.Printf("fibonacci(%d) is: %d\n", i, result)
	}
	hh(10)
}
//根据传入参数n 返回第n个斐波那契数字
func fibonacci(n int) (res int) {
	if n <= 1 {
		res = 1
	} else {
		res = fibonacci(n-1) + fibonacci(n-2)
	}
	return
}
//打印10 - 1
func hh(n int) {
	if n >= 1 {
		println(n)
		n--
		hh(n)
	}
}
fibonacci(0) is: 1
fibonacci(1) is: 1  
fibonacci(2) is: 2  
fibonacci(3) is: 3  
fibonacci(4) is: 5  
fibonacci(5) is: 8  
fibonacci(6) is: 13 
fibonacci(7) is: 21 
fibonacci(8) is: 34 
fibonacci(9) is: 55 
fibonacci(10) is: 89
10                  
9                   
8                   
7                   
6                   
5                   
4                   
3                   
2                   
1 

6.7 将函数作为参数

package main

import (
	"fmt"
)

type ff func(a, b int) (res int)

func main() {
	num1 := mm(add, 10, 5)
	num2 := mm(subtract, 10, 5)
	fmt.Printf("%d\n", num1)
	fmt.Printf("%d\n", num2)
}
func mm(x ff, a, b int) (res int) {
	res = x(a, b)
	return res
}

func add(a, b int) (res int) {
	res = a + b
	return
}
func subtract(a, b int) (res int) {
	res = a - b
	return
}
15
5

6.8 闭包

匿名函数被称为闭包。

当不想给函数起名时,可以使用匿名函数.

这样的函数不能独立存在,将其赋值于某个变量。即保存函数的地址于变量中,然后通过变量名都函数进行调用。

例如

c := func(a, b int) (res int) {
		res = a + b
		return
	}
fmt.Printf("%d\n", c(10, 15))//25

也可以直接对匿名函数进行调用(最后一对括号表示对该匿名函数的调用)

func(a, b int) {
   fmt.Printf("%d\n", a*b)
}(10, 2)
//20

6.9 应用闭包:将函数作为返回值

package main

import (
	"fmt"
	"strings"
)

func f() (ret int) {
	defer func() {
		ret++
	}()
	return 1
}
func main() {
	fmt.Println(f())
	x := ll1()
	fmt.Println(x(1))
	y := ll2(3)
	fmt.Println(y(2))
	z := ll3()
	fmt.Println(z(1))
	fmt.Println(z(10))
	fmt.Println(z(100))
	addBmp := MakeAddSuffix(".bmp")
	addJpeg := MakeAddSuffix(".jpeg")
	fmt.Println(addBmp("file"))
	fmt.Println(addJpeg("file"))
}
func ll1() func(a int) int {
	return func(a int) int {
		return a + 1
	}
}
func ll2(b int) func(a int) int {
	return func(a int) int {
		return a + b
	}
}
func ll3() func(int) int {
	var x int
	return func(c int) int {
		x += c
		return x
	}
}
func MakeAddSuffix(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}
2
2        
5        
1        
11       
111      
file.bmp 
file.jpeg

6.10 计算函数执行时间

使用time包中的Now()和sub函数

func main() {
	start := time.Now()//获取当前时间
	lll1()
	end := time.Now()//获取函数执行完成后时间
	delta := end.Sub(start)//执行时间为 end - start
	fmt.Printf("runtime use time is :%s\n", delta)
}
func lll1() {
	for i := 0; i <= 1000; i++ {
		fmt.Printf("%d\n", i)
	}
}
//runtime use time is :62.7317ms
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值