Golang

函数

函数简介

函数是go语言中的一级公民,我们把所有有的功能菜单都定义在函数中,可以重复使用,函数包含函数的名称,参数列表和返回值类型,这些构成了函数的签名(signature)。

go语言中函数特性

1.go语言中有三种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。
2.go语言中不允许函数重载(overload),也就是说不允许函数重名。
3.go语言中函数不能嵌套函数,但可以嵌套匿名函数。
4.函数是一个值,可以将函数赋值给变量,使得这个函数成为变量。
5.函数可以参数传递给另一个函数。
6.函数得到返回值可以是一个函数。
7.函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。
8.函数参数可以没有名称。

go语言中函数的定义和调用

函数在使用前必须选定义,可以调用函数来完成某个任务。函数可以重复调用,从而达到代码重用。

go语言函数定义语法

func name([list])[return_types] {
	函数体
}

语法解析

  • func : 函数由func开始声明
  • name : 函数名称,函数名和参数列表一起构成了函数签名
  • list : 参数列表,参数就行一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types : 返回类型,函数返回一列值。return_types是该列值得数据类型。有些功能不需要返回值,这种情况下return_types不是必须的。
  • 函数体 : 函数定义的代码集合

函数定义的实例

  • 定义一个求和函数
package main

import "fmt"

func sum(a int, b int) (ret int) {
	ret = a + b
	return ret
}

func main() {
	r := sum(1, 2)
	fmt.Printf("r=%v\n", r)
}
  • 定义一个比较两个数大小的函数
package main

import (
	"fmt"
)

func compare(a int, b int) (max int) {
	if a > b {
		max = a
	} else {
		max = b
	}
	return max
}

func main() {
	r := compare(1, 2)
	fmt.Printf("max=%v\n", r)
}

函数的调用

当我们要完成某个任务时,可以调用函数来完成。调用函数要传递参数,如有返回值可以获取返回值。

func main() {
	r := compare(1, 2)
	fmt.Printf("max=%v\n", r)

	r = sum(1, 2)
	fmt.Printf("r=%v\n", r)
}

函数的返回值

函数可以有0或者多个返回值,返回值需要指定数据类型,返回值通过return关键字来指定。return可以有参数,也可以没有参数,这些返回值可以有名称,也可以没有名称。go中的函数可以有多个返回值。
1.return关键字中指定了参数时,返回值可以不用名称。如果return省略参数,则返回值部分必须带名称
2.当返回值有名称时,必须使用括号包围,逗号分割,即使只有一个返回值
3.即使返回值命名了,return中也可以强制指定其他返回值的名称,也就是说return的优先级更高
4.命名的返回值是预先声明好的 ,在函数内部可以直接使用,无需再次声明。命名返回值的名称不能和函数参数名称相同,否则报错提示变量重复定义
5.return中可以有表达式,但不能出现赋值表达式,这和其他语言可能有所不同。:例如return a+b是正确的,但return c=a+b是错误的
没有返回值

package main

import "fmt"

func hhh() {
	fmt.Println("我既没有返回值也没有参数!!!")
}

func main() {
	hhh()
}

有一个返回值

func hhh(a int, b int) (ret int) {
	ret = a + b
	return ret
}
  • 多个返回值且在return中指定返回的内容
package main

import "fmt"

func hhh() (name string, age string) {
	name = "hhh"
	age = "20"
	return name, age
}

func main() {
	name, age := hhh()
	fmt.Printf("name:%v\n", name)
	fmt.Printf("age:%v\n", age)
}
  • 多个返回值,返回值名称没有被使用
package main

import "fmt"

func hhh() (name string, age string) {
	name = "hhh"
	age = "20"
	return		//等价于return name age 
}

func main() {
	name, age := hhh()
	fmt.Printf("name:%v\n", name)
	fmt.Printf("age:%v\n", age)
}
  • return覆盖命名返回值,返回值名称没有被使用
package main

import "fmt"

func hhh() (string, int) {
	n := "hhh"
	a := 20
	return n, a
}

func main() {
	name, age := hhh()
	fmt.Printf("name:%v\n", name)
	fmt.Printf("age:%v\n", age)
}

函数的参数

go语言函数可以有0个或者多个参数,参数需要指定数据类型。
声明函数时的参数列表叫做形参,调用时传递的参数叫做实参。
go语言是通过传值的方式传参的,意味着传递给函数的是拷贝后的副本,所以函数内部访问,修改的也是这个副本。
go语言可以使用变长参数,有时候并不能确定参数的个数,可以使用变长参数,可以在函数定义语句的参数部分使用ARGS…TYPE的方式。这时将会…代表的参数全部保存到一个名为ARGS的slice中,注意这些参数的数据类型都是TYPE.

package main

import "fmt"
//这时候a,b是形参
func hhh(a int, b int) int {
	return a + b
}

func main() {
	//这时候是实参
	qaz := hhh(1, 2)
	fmt.Printf("a+b=%v\n", qaz)
}
  • 演示参数传递 按值传递
package main

import "fmt"

func hhh(a int) {
	a = 100
}

func main() {
	x := 200
	hhh(x)
	fmt.Printf("x:%v\n", x)
}
  • 变长参数
package main

import "fmt"

func hhh(args ...int) {
	for _, i := range args {
		fmt.Printf("i:%v\n", i)
	}
}

func main() {
	hhh(1, 2, 3, 4, 5, 6, 7)
}
package main

import "fmt"

func hhh(name string, age int, email string, args ...int) {
	fmt.Printf("name=%v\n", name)
	fmt.Printf("age=%v\n", age)
	fmt.Printf("email=%v\n", email)
	fmt.Printf("%v\n", args)
}

func main() {
	hhh("hhh", 20, "hhh@qq.com", 1, 2, 3, 4, 5, 6)
}

函数类型和函数变量

可以使用type关键字来定义一个函数类型,语法个数

type fun func(int,int)int
fun 就是名称随意的

上面语句定义了一个fun函数类型,它是一种数据类型,这种函数接收两个int类型的参数并且返回一个int类型的返回值
下面我们定义两个这样结构的两个函数,一个求和,一个比较大小

package main

import "fmt"

func sum(a int, b int) int {
	return a + b
}
func max(a int, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

func main() {
	type hhh1 func(int, int) int
	var qaz hhh1
	qaz = max
	c := qaz(1, 2)
	fmt.Printf("c:%v\n", c)
	qaz = sum
	c = qaz(1, 2)
	fmt.Printf("c:%v\n", c)
}

高阶函数

go语言的函数,可以作为函数的参数,传递给另外一个函数,作为另外一个函数的返回值返回

  • go语言函数作为参数
package main

import "fmt"

func hhh(name string) {
	fmt.Printf("Hello %v", name)
}

func hh(name string, ff func(name string)) {
	ff(name)
}

func main() {
	hh("hhh", hhh)
}
  • 函数作为返回值
package main

import "fmt"

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

func sub(a int, b int) int {
	return a - b
}

func cal(operator string) func(int, int) int {
	switch operator {
	case "+":
		return add
	case "-":
		return sub
	default:
		return nil
	}
}
func main() {
	ff := cal("+")
	r := ff(1, 2)
	fmt.Printf("r:%v\n", r)
	ff = cal("-")
	r = ff(1, 2)
	fmt.Printf("r:%v\n", r)
}
  • 匿名函数
    go语言中函数不能嵌套,但是在函数内部可以定义匿名函数,实现以下简单调用。
    所谓匿名函数就是,没有名称的函数
    语法格式如下:
func (参数列表)(返回值)

也可以既没有参数,也没有返回值

//匿名函数
package main

import "fmt"

func main() {
	max := func(a int, b int) int {
		if a > b {
			return a
		} else {
			return b
		}
	}
	r := max(1, 2)
	fmt.Printf("r:%v\n", r)
}

//自己调用
package main

import "fmt"

func main() {
	hhh := func(a int, b int) int {
		if a > b {
			return a
		} else {
			return b
		}
	}(1, 2)
	fmt.Printf("hhh:%v\n", hhh)
}

闭包

闭包可以理解成定义在一个函数内部的函数。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。或者说是函数和其引用环境的组合体。
闭包指的是函数和与其相关的引用环境组合而成的实体。简单来说,闭包=函数+引用环境

package main

import "fmt"

func add() func(y int) int {
	var x int
	return func(y int) int {
		x += y
		return x
	}
}
//当调用add函数时add函数的返回值时匿名函数func(y int) 所以f就等于匿名函数。
//当r := f(10)时相当于调用匿名函数。
func main() {
	f := add()
	r := f(10)
	fmt.Printf("c:%v\n", r)
	r = f(20)
	fmt.Printf("c:%v\n", r)
	r = f(30)
	fmt.Printf("c:%v\n", r)
	fmt.Println("-----------------")
	f1 := add()
	r = f1(10)
	fmt.Printf("c1:%v\n", r)
	r = f1(20)
	fmt.Printf("c1:%v\n", r)
}

变量f是一个函数并且它引用了其他外部作用域中的x变量,此时f就是一个闭包。在f的生命周期内,变量x也一直有效

package main

import "fmt"

func hhh(base int) (func(int) int, func(int) int) {
	add := func(a int) int {
		base += a
		return base
	}
	sub := func(a int) int {
		base -= a
		return base
	}
	return add, sub
}

func main() {
	add, sub := hhh(100)
	r := add(100)
	fmt.Printf("r:%v\n", r)
	r = sub(50)
	fmt.Printf("r:%v\n", r)
}

递归

函数内部调用函数自身的函数称为递归函数。
使用递归函数最重要的三点
1.递归就是自己调用自己
2.必须先定义函数的退出条件,没有退出条件,递归将成为死循环。
3.go语言递归函数很有可能会产生一大堆的goroutine,也很有可能会出现栈空间内存溢出。

//for 循环阶乘
package main

import "fmt"

func hhh() {
	var s int = 1
	for i := 1; i <= 5; i++ {
		s *= i
	}
	fmt.Printf("s%v\n", s)

}
func main() {
	hhh()
}
// 递归
package main

import "fmt"

func hhh(a int) int {
	if a == 1 {
		return 1
	} else {
		return a * hhh(a-1)
	}
}

func main() {
	c := hhh(5)
	fmt.Printf("c:%v\n", c)
}
//斐波那契数列
//计算公式为 : f(n)=f(n-1)+f(n-2)且f(2)=f(1)=1
package main

import "fmt"

func hhh(a int) int {
	if a == 1 || a == 2 {
		return 1
	}
	return hhh(a-1) + hhh(a-2)
}

func main() {
	c := hhh(5)
	fmt.Printf("c%v\n", c)
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值