函数
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 listimport "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 listimport "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 listimport "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)
}