[toc] 函数使用 > 函数是Go语言里面的核心设计,它通过关键字func来声明,它的格式如下。 # 1. 函数声明 ``` func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) { //这里是处理逻辑代码 //返回多个值 return value1, value2 } ``` * 关键字func用来声明一个函数funcName。 - 函数可以有一个或者多个参数,每个参数后面带有类型,通过“,”分隔函数可以返回多个值。 - 返回值声明了两个变量output1和output2,如果你不想声明也可以,就保留两个类型声明。 - 如果只有一个返回值且不声明返回值变量,那么你可以省略“包括返回值”的括号 - 如果没有返回值,就直接省略最后的返回信息。 - 如果有返回值,那么必须在函数的外层添加return语句。 # 2. 接收变参的函数 ``` func funcName(input ...type) (output1 type1, output2 type2) { //这里是处理逻辑代码 //返回多个值 return output1 type1, output2 type2 } ``` > 注意,这些参数的类型全部是type。在函数体中,变量input是一个type的slice。 - 使用示例 ``` package main import "fmt" func main() { result := joinStr("h", "e", "l", "l", "o") fmt.Println(result) // hello } func joinStr(input ...string) (strRes string) { for _, v := range input { strRes += v } return } ``` # 3.参数传递 > Go 默认使用按值传递参数,也就是传递参数的副本。函数接收参数副本之后,在使用变量的过程中可能对副本的值进行更改,但不会影响到原来的变量。如果想要影响到原来的变量,则需要传指针。<font color=red>需要注意的是:切片(slice)、字典(map)、接口(interface)、通道(channel)这样的引用类型都是默认使用引用传递(即使没有显示的指出指针)</font> ## 3.1 按值传递使用示例 ``` package main import "fmt" func main() { str := "good morning" updateStr(str) fmt.Println(str) // good morning } func updateStr(str string) string { str = "good evening" return str } ``` ## 3.2 按引用使用示例 ``` package main import "fmt" func main() { str := "good morning" updateStr(&str) fmt.Println(str) // good evening } func updateStr(str *string) string { *str = "good evening" return *str } ``` # 4.延迟语句(defer)的使用 >Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句。当函数执行到最后时,这些 defer 语句会按照逆序执行,最后该函数返回。特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题。 ## 4.1 使用示例 ``` package main import ( "fmt" "os" "io/ioutil" ) func main() { filePath := "/Users/liuqh/Desktop/test.json" str := openFile(filePath) fmt.Println(str) //输出以下内容 //defer 被调用了 //文件里的内容 } func openFile(filePath string) string { //打开文件 file, err := os.Open(filePath) if err != nil { fmt.Println("open file err") } //利用defer 关闭文件 defer testDefer(file) content, err := ioutil.ReadAll(file) if err != nil { fmt.Println("read file err") } return string(content) } func testDefer(file *os.File) { fmt.Println("defer 被调用了") file.Close() } ``` ## 4.2 函数中使用多个defer > 如果有一个函数中有多个地方调用defer,那么defer采用后进先出(逆序执行) ``` package main import ( "fmt" ) func main() { testDefer() // 5 4 3 2 1 } func testDefer() { for i := 1; i < 6; i++ { defer fmt.Println(i) } } ``` # 5.函数作为值、类型 >在Go语言中函数也是一种变量,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值。 ``` go type typeName func(input1 inputType1,input2 inputType2[,...])(result1 resultType1 [, ...]) ``` ## 5.1 使用示例 ``` package main import "fmt" type testInt func(int) bool func main() { numSlice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} odd := filter(numSlice, isOdd) event := filter(numSlice, isEvent) fmt.Println(odd) // [2 4 6 8] fmt.Println(event) // [1 3 5 7 9] } func isOdd(num int) bool { if num%2 == 0 { return true } return false } func isEvent(num int) bool { if num%2 == 0 { return false } return true } func filter(arg []int, funcName testInt) []int { var result []int for _, v := range arg { if funcName(v) { result = append(result, v) } } return result } ``` # 6.匿名函数 既没有名称的函数 ## 6.1 使用示例 ``` package main import "fmt" func main() { f := func(a,b int) int{ i := a + b return i } fmt.Println(f(1,4)) // 5 } ```