golang 函数

1、包

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

包的做用

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

2、函数细节

  • 函数自己也是一种数据类型,能够赋值给一个变量,该变量就是一个函数类型的变量,经过该变量能够对函数调用
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     // 好处是不用管返回的顺序,接收按顺序接收就行

}

3、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()...")

}

3、匿名函数

若是但愿函数只使用一次,能够考虑匿名函数,匿名函数也可实现屡次调用。框架

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()...")

}

3、闭包

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

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

}

上面代码说明:spa

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

返回的是一个匿名函数,但这个匿名函数引用到函数外的n,所以这个匿名函数就和n造成一个总体,构成闭包设计

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

4、函数中的defer

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

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

}

5、函数的参数传递

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

6、错误处理

Go中引入处理方式是defer,panic,recover
Go中能够抛出一个panic的异常,而后在defer中经过recover捕获这个异常,而后正常处理blog

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

}
相关文章
相关标签/搜索