函数
函数定义
1 2 3 4 5
| func function_name(input1 type1, input2 type2) (type1, type2) { return value1, value2 }
|
- 函数用
func 声明。
- 函数可以有一个或多个参数,需要有参数类型,用
, 分割。
- 函数可以有一个或多个返回值,需要有返回值类型,用
, 分割。
- 函数的参数是可选的,返回值也是可选的。
值传递
传递参数时,将参数复制一份传递到函数中,对参数进行调整后,不影响参数值。
Go 语言默认是值传递。
引用传递
传递参数时,将参数的地址传递到函数中,对参数进行调整后,影响参数值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package main
import ( "encoding/json" "fmt" )
type Result struct { Code int `json:"code"` Message string `json:"msg"` }
func main() { var res Result res.Code = 200 res.Message = "success" toJson(&res) setData(&res) toJson(&res) }
func setData (res *Result) { res.Code = 500 res.Message = "fail" }
func toJson (res *Result) { jsons, errs := json.Marshal(res) if errs != nil { fmt.Println("json marshal error:", errs) } fmt.Println("json data :", string(jsons)) }
|
运行结果:
1 2 3
| PS D:\Project\godemo> go run pointer.go json data : {"code":200,"msg":"success"} json data : {"code":500,"msg":"fail"}
|
返回值
示例,实现2个数的加法(一个返回值)和除法(多个返回值):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package main
import "fmt"
func add(num1 int, num2 int) int { return num1 + num2 }
func div(num1 int, num2 int) (int, int) { return num1 / num2, num1 % num2 } func main() { quo, rem := div(100, 17) fmt.Println(quo, rem) fmt.Println(add(100, 17)) }
|
运行结果:
1 2 3
| PS D:\Project\godemo> go run return_demo.go 5 15 117
|
也可以给返回值命名,简化 return,例如 add 函数可以改写为
1 2 3 4
| func add(num1 int, num2 int) (ans int) { ans = num1 + num2 return }
|
错误处理(error handling)
如果函数实现过程中,如果出现不能处理的错误,可以返回给调用者处理。比如我们调用标准库函数os.Open读取文件,os.Open 有2个返回值,第一个是 *File,第二个是 error, 如果调用成功,error 的值是 nil,如果调用失败,例如文件不存在,我们可以通过 error 知道具体的错误信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package main
import ( "fmt" "os" )
func main() { _, err := os.Open("filename.txt") if err != nil { fmt.Println(err) } }
|
文件不存在时,运行结果:
1 2
| PS D:\Project\godemo> go run error_demo.go open filename.txt: The system cannot find the file specified.
|
可以通过 errorw.New 返回自定义的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package main
import ( "errors" "fmt" )
func hello(name string) error { if len(name) == 0 { return errors.New("error: name is null") } fmt.Println("Hello,", name) return nil }
func main() { if err := hello(""); err != nil { fmt.Println(err) } }
|
运行结果:
1 2
| PS D:\Project\godemo> go run error_demo1.go error: name is null
|
error 往往是能预知的错误,但是也可能出现一些不可预知的错误,例如数组越界,这种错误可能会导致程序非正常退出,在 Go 语言中称之为 panic。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package main
import "fmt"
func get(index int) int { arr := [3]int{2, 3, 4} return arr[index] }
func main() { fmt.Println(get(5)) fmt.Println("finished") }
|
运行结果:
1 2 3 4 5 6 7 8 9
| PS D:\Project\godemo> go run error_demo2.go panic: runtime error: index out of range [5] with length 3
goroutine 1 [running]: main.get(...) D:/Project/godemo/error_demo.go:7 main.main() D:/Project/godemo/error_demo.go:11 +0x1d exit status 2
|
- 在 get 函数中,使用 defer 定义了异常处理的函数,在协程退出前,会执行完 defer 挂载的任务。因此如果触发了 panic,控制权就交给了 defer。
- 在 defer 的处理逻辑中,使用 recover,使程序恢复正常,并且将返回值设置为 -1,在这里也可以不处理返回值,如果不处理返回值,返回值将被置为默认值 0。
计算 MD5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package main
import ( "crypto/md5" "encoding/hex" "fmt" )
func MD5(str string) string { s := md5.New() s.Write([]byte(str)) return hex.EncodeToString(s.Sum(nil)) }
func main() { str := "12345" fmt.Printf("MD5(%s): %s\n", str, MD5(str)) }s
|
运行结果:
1 2
| PS D:\Project\godemo> go run md5_demo.go MD5(12345): 827ccb0eea8a706c4c34a16891f84e7b
|
获取时间戳
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package main
import ( "fmt" "time" )
func getTimeInt() int64 { return time.Now().Unix() } func getTimeStr() string { return time.Now().Format("2006-01-02 15:04:05") }
func main() { fmt.Printf("current time str : %s\n", getTimeStr()) fmt.Printf("current time unix : %d\n", getTimeInt()) }
|
运行结果:
1 2 3
| PS D:\Project\godemo> go run timestamp.go current time str : 2021-08-10 22:14:40 current time unix : 1628604880
|
生成签名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package main
import ( "crypto/md5" "encoding/hex" "fmt" "sort" )
func main() { params := map[string]interface{} { "name" : "Tom", "pwd" : "123456", "age" : 30, } fmt.Printf("sign : %s\n", createSign(params)) }
func MD5(str string) string { s := md5.New() s.Write([]byte(str)) return hex.EncodeToString(s.Sum(nil)) }
func createSign(params map[string]interface{}) string { var key []string var str = "" for k := range params { key = append(key, k) } sort.Strings(key) for i := 0; i < len(key); i++ { if i == 0 { str = fmt.Sprintf("%v=%v", key[i], params[key[i]]) } else { str = str + fmt.Sprintf("&xl_%v=%v", key[i], params[key[i]]) } } var secret = "123456789"
sign := MD5(MD5(str) + MD5(secret)) return sign }
|
运行结果:
1 2
| PS D:\Project\godemo> go run sign.go sign : 33b940c8f18ede393ea34cd45c406db4
|