一、golang函数
函数包括函数的名称、参数列表和返回值类型。这些构成了函数的签名
1.1go语言中函数特性
- go语言中有三种函数:普通函数、匿名函数(没有名的函数)、方法(定义在struct上的函数)
- go语言中不允许函数重载,即不允许函数同名
- go语言中的函数不能嵌套函数,但可以嵌套匿名函数
- 函数是一个值,可以将函数赋值给变量,使这个变量也成为函数
- 函数可以作为参数传递给另一个函数(因为函数是一个值)
- 函数的返回值可以是一个函数
- 函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数
- 函数参数可以没有名称
1.2go语言中函数的定义和调用
1.2.1定义语法
func function_name( [ parameter list ] ) [return_types]{
函数体
}
示例
package main
import (
"fmt"
)
/*
函数
*/
func sum(a int,b int)(ret int){
//参数 a,b;返回值 ret
ret =a+b
return ret
}
func comp(a int,b int)(maxNum int){
if a>b{
maxNum=a
}else{
maxNum=b
}
return maxNum
}
func main() {
r:=sum(1,2)
fmt.Printf("r:%v\n", r)
r1:=comp(3,4)
fmt.Printf("r1:%v\n", r1)
}
1.3golang中的返回值的情况
- 没有返回值
- 有一个返回值
- 有多个返回值
package main
import (
"fmt"
)
/*
函数---返回值
*/
//没有返回值
func f1(){
fmt.Println("没有返回值")
}
//有一个返回值 返回值可以给名称,也可以不给名称
func sum1(a int,b int)(ret int){
ret=a+b
return ret
}
func sum2(a int,b int)(int){
ret:=a+b
return ret
}
func sum3(a int,b int)(int){
return a+b
}
//多个返回值
func f3()(name string,age int){
name="tom"
age=20
return name,age
//return return=return name,age
}
//return可以覆盖命名返回值,返回值名称没有被使用
func f4()(name string,age int){
n:="tom"
a:=20
return n,a
}
func main() {
f1()
name,age:=f3()
fmt.Printf("%v %v", name,age)
name1,age1:=f3()
fmt.Printf("%v %v", name1,age1)
}
1.4参数的情况
- go语言是通过传值的方式传参的,意味着传递给函数的是拷贝后的副本,所以函数内部访问、修改的也是这个副本。对于一般的数据类型,例如int、string来说,在函数中的改变不影响变量本身,但是对于slice、指针等引用数据类型,在函数中的改变也会改变该变量本身
- go语言可以使用变长参数,使用args...type的方式,这是会将...代表的参数全部保存到一个名为ages的slice中,注意这些参数的数据类型都是type
示例
package main
import (
"fmt"
)
/*
函数---参数
*/
func sum(a int,b int) int{
return a+b
}
//参数的传递是传递值,
//也就是说在函数中改变的是参数的副本,不会改变变量本身
func f1(a int){
a=200
}
//对于参数是指针、引用、切片等,都是指针类型,
//在函数中改变后,变量本身也改变
func f2(a []int){
a[0]=100
}
//变长参数 必须是一个数据类型,使用...表示
func f3(args...int){
for _, v := range args {
fmt.Printf("%v\n", v)
}
}
func f4(name string,ok bool,args...int){
fmt.Printf("name:%v\n", name)
fmt.Printf("ok:%v\n", ok)
for _, v := range args {
fmt.Printf("args:%v\n", v)
}
}
func main() {
r:=sum(1,2)
fmt.Printf("%v\n", r)
a:=100
f1(a)
fmt.Printf("%v\n", a) //100 说明不会改变
var b=[]int{0,1,2,3}
f2(b)
fmt.Printf("%v\n", b) //[100 1 2 3] 说明改变了
f3(1,2,3,4)
f3(7,8,9)
f4("zxx",true,1,2,3,4)
}
1.5函数类型和函数变量
可以使用type关键字来定义一个函数类型
type fun func(int,int) int
上面语句定义了一个fun函数类型,接受两个int类型的范数,并且返回一个int类型的返回值
package main
import (
"fmt"
)
/*
定义一个fun函数类型,把sum和max赋值给他
*/
//定义一个函数类型
type fun func(int,int) int
func sum(a int,b int)(ret int){
//参数 a,b;返回值 ret
ret =a+b
return ret
}
func comp(a int,b int)(maxNum int){
if a>b{
maxNum=a
}else{
maxNum=b
}
return maxNum
}
func main() {
var f fun //f是一个fun类型的函数变量
f=sum
s:=f(1,2)
fmt.Printf("%v\n", s) //3
f=comp
m:=f(4,5)
fmt.Printf("%v\n", m) //5
}
1.6golang高阶函数
go语言中的函数,可以作为函数的参数,也可以作为另一个函数的返回值返回
package main
import (
"fmt"
)
/*
golang高阶函数
*/
//go语言函数作为参数
func sayhello(name string){
fmt.Println(name)
}
func f1(name string, f func(string)){
f(name)
fmt.Printf("%v", name)
}
//函数作为返回值
func add(a int,b int)int{
return a+b
}
func sub(a int,b int)int{
return a-b
}
//返回值是一个函数
func call(operator string) func(int,int) int{
switch operator {
case "+":
return add
case "-":
return sub
default:
return nil
}
}
func main() {
f1("tom",sayhello) //直接给函数名称就可以了
ff:=call("+")
r:=ff(1,2)
fmt.Printf("%v", r)
}
1.7golang匿名函数
go语言函数不能嵌套,但是在函数内部可以定义匿名函数,实现一下简单功能调用
所谓匿名函数就是没有名称的函数
语法格式:
func (参数列表)(返回值)
package main
import (
"fmt"
)
/*
golang高阶函数
*/
func f1(){
name:="zxx"
age:="20"
//匿名函数,在函数内部做一些运算
f1:=func()string{
return name+age
}
msg:=f1()
fmt.Printf("%v", msg)
}
func main() {
//匿名函数 用法一 没有函数名称
max:=func(a int,b int) int{
if a>b{
return a
}else{
return b
}
}
r:=max(1,2)
fmt.Printf("%v\n", r) //2
//用法二:自己调用自己
r1:=func(a int,b int) int{
if a>b{
return a
}else{
return b
}
}(1,2)
fmt.Printf("%v\n", r1)
f1()
}
1.8golang闭包
闭包可以理解为定义在一个函数内部的函数。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。或者说是函数和引用环境的组合体 闭包=函数+引用环境
package main
import (
"fmt"
)
/*
golang闭包
*/
func add()func(y int)int{
//返回值是 func(y int)int 即形参是int,返回值是int的函数
var x int
return func(y int) int{
x+=y
return x
}
}
func main() {
f:=add() //调用add返回了一个函数,这个函数就是func(y int) int
r:=f(10) //形参10,即y=10
fmt.Printf("r:%v\n", r) //10
r=f(20)
fmt.Printf("r:%v\n", r) //30 之前的10被保存下来了,保存到x中
r=f(30)
fmt.Printf("r:%v\n", r) //60 30+30=60 只要这个函数一直存在,那么就会一直保存一个x
fmt.Println("--------------------")
f1:=add() //重新调用了一次 x中之前存在值就被清空了
fmt.Println(f1(40)) //40
fmt.Println(f1(50)) //90
}
进阶
package main
import (
"fmt"
)
/*
golang闭包
*/
func cal(base int)(add func (a int)int,sub func (a int)int){
add=func(i int)int{
base+=i
return base
}
sub=func(i int)int{
base-=i
return base
}
return add,sub
}
func main() {
add,sub:=cal(10)
fmt.Printf("%v %v\n", add(1),sub(2)) //11 9
fmt.Printf("%v %v\n", add(3),sub(1)) //12 11
}
1.9递归
package main
import (
"fmt"
)
/*
golang递归
*/
func f1(){
var s int = 1
//阶乘的for实现
for i := 1; i <=5; i++ {
s*=i
}
fmt.Printf("%v\n", s)
}
//使用递归实现
func f2(a int) int{
//返回条件
if a==1{
return 1
}else{
return a*f2(a-1)
}
}
//斐波那契数列的实现
func f3(a int) int{
if a==1||a==2{
return 1
}else{
return f3(a-1)+f3(a-2)
}
}
func main() {
f1() //120
r:=f2(5)
fmt.Printf("%v\n", r) //120
r1:=f3(10)
fmt.Printf("%v\n", r1) //55
}
二、特殊语句
2.1defer语句
defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行。也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行
2.1.1defer特性
2.1.2defer用途
package main
import (
"fmt"
)
/*
defer
*/
func main() {
fmt.Println("start")
defer fmt.Println("step1")
defer fmt.Println("step2")
defer fmt.Println("step3")
fmt.Println("end")
}
/*
start
end
step3
step2
step1
可以看到defer语句在return之前才会被执行,并且按照defer的先后逆序执行
*/
2.2init函数
先于main函数执行,实现包级别的一些初始化操作
2.2.1init函数的主要特点
示例函数
package main
import (
"fmt"
)
/*
init
*/
//init初始化顺序:变量->init->main
var i int = initVar()
func init(){
fmt.Println("init")
}
func initVar()int{
fmt.Println("initVar")
return 100
}
func main() {
fmt.Println("main")
}
/*
initVar
init
main
可以看出init先于main执行
*/