golang 函数

一、包

go的每一个文件都是属于一个包的,也就是说go是以包的形式来管理文件和项目目录结构的。

包的作用

  1. 区分相同名字的函数、变量等标识符
  2. 当程序文件较多,可很好的管理项目
  3. 控制函数、变量等访问范围,即作用域

二、函数细节

  • 函数本身也是一种数据类型,可以赋值给一个变量,该变量就是一个函数类型的变量,通过该变量可以对函数调用
func getSum(n1 int, n2 int) int {

 return n1 + n2

}

func myFunc(funcvar func(int, int) int, num1 int,num2 int) {

 return funcvar(num1, num2)

}

func main() {

 res := myFunc(getSum, 2, 4)

 fmt.Println("a的类型是%T, getSum 的类型是%T", a, getSum)

}
  • 为了简化数据类型定义,go支持自定义数据类型
type myInt int

 var num1 myInt

 var num2 int

 num1 = 40
 num2 = int(num1) // myInt 和int是两个类型,所以要强转
  • 支持对函数返回值命名
func getSumAndSub(n1 int, n2 int) (sum int, sub int) {

 sum = n1 + n2

 sub = n1 - n2

 return     // 好处是不用管返回的顺序,接收按顺序接收就行

}

三、init函数

每一个源文件都可以有一个init函数,该函数会在main函数执行前,被Go框架调用。
如果一个文件包含全局变量定义,init函数和main函数,则执行流程是 变量定义>init函数>main函数,如果main.go 引入了包,则执行流程是 包的变量定义>包的init函数>main的变量定义>main的init函数>main的main函数

func init() {

 fmt.Println("init()...")

}

func main() {

 fmt.Println("main()...")

}

三、匿名函数

如果希望函数只使用一次,可以考虑匿名函数,匿名函数也可实现多次调用。

var (
// 全局匿名函数
 Func1 := func (n1 int, n2 int) int {

 return n1 + n2

 }

)

func main() {

 // 在定义匿名函数时直接调用, 这种方式匿名函数只能调用一次

 result := func (n1 int, n2 int) int {

 return n1 + n2

 }(n1, n2)

 // 将匿名函数func (n1 int, n2 int) int 赋值给a变量,则a的数据类型就是函数类型,此时可通过a进行调用

 a := func (n1 int, n2 int) int {

 return n1 + n2

 }

 res := a(10, 20)

 fmt.Println("main()...")

}

三、闭包

一个函数和其相关的引用环境组合的一个整体(实体)

func AddUpper() func (int) int {

 var n int = 10;

 return func (x int) int {

 n = n + x

 return n

 }

}

func main() {

 f := AddUpper()

 fmt.Println(f(1)) // 11

 fmt.Println(f(2)) // 13

}

上面代码说明:

  1. AddUpper是个函数,返回的数据类型是func(int) int
  2. image.png

返回的是一个匿名函数,但这个匿名函数引用到函数外的n,因此这个匿名函数就和n形成一个整体,构成闭包

  1. 可以理解闭包是一个类,函数是操作,n是字段,函数和它使用到的n构成闭包
  2. 当我们反复调用f函数时,因为n只初始化一次,因此每调用一次就进行累计
  3. 要搞清楚闭包的关键,就是要分析出返回的函数它使用(引用)到哪些变量,因为函数和它引用到的变量共同构成闭包

四、函数中的defer

在函数中,经常要创建资源(数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时释放资源。Go的设计者提供defer(延时机制)

func sum (n1 int, n2 int) int {

 // 当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈(defer栈)

 // 当函数执行完毕后,再从defer栈,按照先入后出的方式出栈,执行

 defer fmt.Println("n1 = ", n1)

 defer fmt.Println("n2 = ", n2)

 return n1 + n2

}

func main() {

 res := sum(10, 20)

 fmt.Printf("%T, %T", f, a) // 151

}

五、函数的参数传递

  1. 值类型:默认值传递,变量直接存储值,内存通常在栈中分配
  2. 引用类型:默认引用传递,变量存储的是一个地址,这个地址对应的空间才真正存储数据,内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾由GC回收

六、错误处理

Go中引入处理方式是defer,panic,recover
Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理

func test () {

 defer func() {

 err := recover() // 内置函数,可以捕获到异常

 if err != nil { // 捕获到错误

 fmt.Println("err=", err)

 }

 }()

 num1 := 10

 num2 := 0

 res := num1 / num2

 fmt.Println("res", res)

}

func main() {

 test()

 fmt.Printf("%T, %T", f, a) // 151

}

你可能感兴趣的:(函数)