函数
1. 格式
func funcName(形参1 type[, 形参2 type...]) [([[返回变量1] type[, [返回变量2] type...]])] {
[return [返回变量1[, 返回变量2...]]]
}
a. 如果形参类型都一样,可以这样写: 形参1, 形参2 type, 同时返回变量也一样
b. 如果只有一个返回值或者无返回值, 可以去掉对应的()
c. 如果返回有返回值,该函数中最外层要有return语句
d. 返回语句(), 返回变量名可以省略
e. []表示可省略
f. 不支持默认参数
example code list
2. 调用其他包中的函数
先引入包,再调用:
包名.函数()
go语言中规则:小写字母开头的函数(变量/类型)只在本包中可见,大写字母开关的可以在其他包中被调用
如果把数字转换为字符串,用strconv.itoa() b := 66 strconv.Itoa(b) = "66"
如果用string(b)结果为 "B"
example code list
3. 多个返回值
go支持多个返回值
如: for k, v := range array ...
a. 如果不想要某个返回值,可以用 "_" 代替,如 for _, v := range array...,不能直接写为这样 for , v :=range array...,但可以省略 v(值), 写为 for k := range array...
b. 如果普通函数返回n个值时,不能用少于n个变量去接收
c. 不能直接打印有多个返回值的函数调用结果
d. 如果定义了返回值的变量名,就可以省略 return 语句后面的返回列表
4. 变参
在调用函数时,参数个数不固定
4.1 参数类型一样
4.2 参数类型不一样
func func1(var ...interface{})
用...interface{}表示任意类型,在 switch 参数.(type) {...}可以判断/得到变量的类型
或者
func func1(varName1 type, varName2 ...type)
比如第一个参数类型确定,后面参数个数不确定
func func1(s string, args ...int)//调用func1("hello", 1) 或者 func1("hello", 1, 2, 3)等等
4.3 变参函数中调用[其他]变参函数
5. 值传递与引用(指针)传递
在参数传递的过程中,都会把参数复制一份,只不过有可能是值,有可能为地址
如果是传地址,则操作同一地址的值,传递的参数可能会发生改变
如果是值类型变量,传地址用:
example code list
6. 函数作为值/类型
6.1 函数作为值
7. defer
defer声明的语句会存在类型于栈的结构中,先进后出,在函数快执行完毕(或者return)时执行,类型于析构函数
格式
defer 表达式|函数
常用于文件关闭等操作,还有重要的 recover 函数
example code list
8. panic 和 recover
go语言中无异常处理,使用 panic 和 recover 处理
panic 使程序进入 panic 状态,recover 使程序从 panic 状态恢复正常
8.1 panic
panic("message") //手动中断程序,抛出 panic,但是 defer 会正常执行,参数可以是任意类型的
注:如果程序出错,也可能会出现 panic
8.2 recover
recover 仅在 defer 函数中有效,无参数
一般用法:
9. 补map交换key与value
map中元素没有顺序
example code list
1. 格式
func funcName(形参1 type[, 形参2 type...]) [([[返回变量1] type[, [返回变量2] type...]])] {
[return [返回变量1[, 返回变量2...]]]
}
a. 如果形参类型都一样,可以这样写: 形参1, 形参2 type, 同时返回变量也一样
b. 如果只有一个返回值或者无返回值, 可以去掉对应的()
c. 如果返回有返回值,该函数中最外层要有return语句
d. 返回语句(), 返回变量名可以省略
e. []表示可省略
f. 不支持默认参数
example code list
import "fmt" func main() { //1. 函数的调用,多个返回值 var ( a = 10 b = 100 ) a2, b2 := add(a, b) fmt.Println("a2, b2 = ", a2, ", ", b2) // a2, b2 = 20, 200 //fmt.Println("a2, b2 = ", add(a, b)) //compile error: multiple-value add() in single-value context } func add(n1, n2 int) (res1, res2 int) { res1, res2 = n1*2, n2*2//不需要用 ":=" 声明, 如果写为res1, res2 := n1*2, n2*2会出错 return } /* //下面的add也可以为上面的写法 func add(n1, n2 int) (res1, res2 int) { return n1*2, n2*2 } */
2. 调用其他包中的函数
先引入包,再调用:
包名.函数()
go语言中规则:小写字母开头的函数(变量/类型)只在本包中可见,大写字母开关的可以在其他包中被调用
如果把数字转换为字符串,用strconv.itoa() b := 66 strconv.Itoa(b) = "66"
如果用string(b)结果为 "B"
example code list
import ( "fmt" "math" "strconv" ) func main() { //2. 调用 math, strconv 包中的函数 fmt.Printf("sqrt(%d) = %.2f\n", b, math.Sqrt(float64(b))) //sqrt(100) = 10.00 c := 67 fmt.Println("string(67) = ", string(c)) //string(67) = C fmt.Println("strconv.Itoa(67) = ", strconv.Itoa(c)) //strconv.Itoa(67) = 67 }
3. 多个返回值
go支持多个返回值
如: for k, v := range array ...
a. 如果不想要某个返回值,可以用 "_" 代替,如 for _, v := range array...,不能直接写为这样 for , v :=range array...,但可以省略 v(值), 写为 for k := range array...
b. 如果普通函数返回n个值时,不能用少于n个变量去接收
c. 不能直接打印有多个返回值的函数调用结果
d. 如果定义了返回值的变量名,就可以省略 return 语句后面的返回列表
4. 变参
在调用函数时,参数个数不固定
4.1 参数类型一样
func1(var1[, var2...]) func func1(varName ...type) { //语句 } ...type = []type,相当于 slice
4.2 参数类型不一样
func func1(var ...interface{})
用...interface{}表示任意类型,在 switch 参数.(type) {...}可以判断/得到变量的类型
或者
func func1(varName1 type, varName2 ...type)
比如第一个参数类型确定,后面参数个数不确定
func func1(s string, args ...int)//调用func1("hello", 1) 或者 func1("hello", 1, 2, 3)等等
4.3 变参函数中调用[其他]变参函数
func func1(varName ...type) { func2(varName...) //原样 func3(varName[i:j]...) //切片 }example code list
import "fmt" func main() { //3. 变参 //3.1 同类型 uncert(1, 3, 5) uncert(2, 4) //3.2 不同类型 uncert2(10.01, "Hello") uncert3("hello", 1) uncert3("hello", 1, 2, 3) } func uncert(args ...int) { for k, v := range args { fmt.Printf("%d => %d\n", k, v) } /** * 结果为: * uncert(1, 3, 5) | uncert(2, 4) * 0 => 1 | 0 => 2 * 1 => 3 | 1 => 4 * 2 => 5 */ for k := range args { fmt.Printf("%d\n", k) } /** * 结果为: 参数(slice)的下标 * uncert(1, 3, 5) | uncert(2, 4) * 0 | 0 * 1 | 1 * 2 */ uncert2(args[1:2]) //切片 } func uncert2(args ...interface{}) { for k, v := range args { fmt.Println(k, " => ", v) } /** * 结果为: 参数(slice)的下标 * uncert2(args[1:2]) * uncert2(3) | uncert2(4) * 0 => [3] | 0 => [4] * * uncert2(10.01, "Hello") * 0 => 10.01 * 1 => Hello */ } func uncert3(s string, n ...int) { for _, v := range n { fmt.Println(s, v) } /** * 结果为: * uncert3("hello", 1) * hello 1 * * uncert3("hello", 1, 2, 3) * hello 1 * hello 2 * hello 3 */ }
5. 值传递与引用(指针)传递
在参数传递的过程中,都会把参数复制一份,只不过有可能是值,有可能为地址
如果是传地址,则操作同一地址的值,传递的参数可能会发生改变
如果是值类型变量,传地址用:
func1(&varName) func func1(varName *type) { //操作指针 //*varName 代替原来的varName }用 "&" 取变量地址,用 "*" 通过指针访问变量
example code list
import "fmt" func main() { //4. 传值/地址 hi := "hello" changeString(hi) fmt.Println("changeString(hi) = ", hi) //changeString(hi) = hello changeStringByAddr(&hi) fmt.Println("changeStringByAddr(&hi) = ", hi) //changeStringByAddr(&hi) = world } func changeString(str string) { str = "world" } func changeStringByAddr(str *string) { *str = "world" }
6. 函数作为值/类型
6.1 函数作为值
varName := funcName varName() //就相当于调用funcName() func funcName() {...}6.2 函数作为类型
type typeName func(参数) (返回列表)6.3 匿名函数/闭包
varName := func() {...} varName() //调用匿名函数 //匿名函数也可以作为一个返回值赋值给变量 func func1(m int) func(int) int { return func2(n int) int { return m + n } } varName := func1(m) //func1(m)返回的结果就是func2函数 varName(n)//就相当于下面这个函数 func2(n int) int { return m + n//m在func1(m)已确定值 }example code list
import "fmt" func main() { //5. 函数作为值/类型 //匿名函数 varFunc := testFunc varFunc() //闭包 varFunc1 := closure(10) fmt.Println(varFunc1(20)); //30 /**************************/ /*运行结果: */ /*func as a var */ /*30 */ /**************************/ } func testFunc() { fmt.Println("func as a var") } func closure(m int) func(int) int { return func(n int) int { return m + n } }
7. defer
defer声明的语句会存在类型于栈的结构中,先进后出,在函数快执行完毕(或者return)时执行,类型于析构函数
格式
defer 表达式|函数
常用于文件关闭等操作,还有重要的 recover 函数
example code list
import "fmt" func main() { //6. defer testDefer() /**************************/ /*运行结果: */ /*defer start */ /*defer end */ /*3 */ /*2 */ /*1 */ /**************************/ } func testDefer() { fmt.Println("defer start") defer fmt.Println("1") defer fmt.Println("2") defer fmt.Println("3") fmt.Println("defer end") }
8. panic 和 recover
go语言中无异常处理,使用 panic 和 recover 处理
panic 使程序进入 panic 状态,recover 使程序从 panic 状态恢复正常
8.1 panic
panic("message") //手动中断程序,抛出 panic,但是 defer 会正常执行,参数可以是任意类型的
注:如果程序出错,也可能会出现 panic
8.2 recover
recover 仅在 defer 函数中有效,无参数
一般用法:
defer func() { if err := recover(); err != nil { //其他处理 } }()example code list
import "fmt" func main() { //7. panic recover echoA() echoB() echoC() /**************************/ /*运行结果: */ /*It is A */ /*recover: It is B */ /*It is C */ /**************************/ } func echoA() { fmt.Println("It is A") } func echoB() { defer func() { if err := recover(); err != nil { fmt.Println("recover: It is B") } }() panic("It is B") //注意顺序,要在 recover 后面 } func echoC() { fmt.Println("It is C") }如果没有defer func() {...}结果如下所示:
9. 补map交换key与value
map中元素没有顺序
example code list
import "fmt" func main() { //8. 补map交换key与value changeKeyVal() /***********************************************/ /*运行结果: (无顺序) */ /*map[3:c 2:b 1:a 4:d] map[c:3 b:2 d:4 a:1] */ /***********************************************/ } //交换map中的键和值 //注意:无序 func changeKeyVal() { m1 := map[int]string{1:"a", 2:"b", 3:"c", 4:"d"} m2 := make(map[string]int) for k, v := range m1 { m2[v] = k } fmt.Println(m1, m2) }
有疑问加站长微信联系(非本文作者)