声明
func name(parameter-list) (result-list) {
body
}
4种方法声明拥有2个int型参数和1个int型返回值的函数
func add(x int, y int) int {
return x + y}
func sub(x, y int) (z int) {
z = x - y; return}
func first(x int, _ int) int {
return x } // _表示该参数没被使用
func zero(int, int) int {
return 0 }
fmt.Printf("%T\n", add) // "func(int, int) int"
fmt.Printf("%T\n", sub) // "func(int, int) int"
fmt.Printf("%T\n", first) // "func(int, int) int"
fmt.Printf("%T\n", zero) // "func(int, int) int"
实参通过值的方式传递,因此函数的形参是实参的拷贝。对形参进行修改不会影响实参。但是,如果实参包括引用类型,如指针,slice(切片)、map、function、channel等类型,实参可能会由于函数的间接引用被修改。
package main
import (
"fmt"
)
// slice
func SliceTest(str []string) {
for k,_ :=range str{
str[k] = "1" // 外部slice会发生改变,说明str为传地址
}
fmt.Println(str) // [1 1 1 1 1]
str = append(str, "abc") // 外部slice不会发生变化,因为append返回的是新slice
fmt.Println(str) // [1 1 1 1 1 abc]
fmt.Printf("str address = %p\n", str) // str address = 0xc000046050
fmt.Printf("str2 address = %p\n", str2) // str2 address = 0xc0000580a0
str = str2 // 如果单纯的地址赋值地址,那么改变的是局部变量,因为地址,只是个十六进制数
fmt.Printf("str address = %p\n", str) // str address = 0xc0000580a0
}
// map 传址
func mapf(m map[string]int) {
m["eee"] = 5
}
func main() {
list := make([]string, 30)
// 待处理的字符串列表
list = []string{
"go scanner",
"go parser",
"go compiler",
"go printer",
"go formater",
}
fmt.Println(list) // [go scanner go parser go compiler go printer go formater]
SliceTest(list)
fmt.Println(list) // [1 1 1 1 1]
// map
m := make(map[string]int)
m["123"] = 2
m["abc"] = 1
mapf(m)
fmt.Println(m) // map[123:2 abc:1 eee:5]
}
多返回值
如果一个函数将所有的返回值都显示的变量名,那么该函数的return语句可以省略操作数
package main
import (
"fmt"
)
func f(x, y int) (add, minus int) {
add = x + y
minus = x - y
return // return add, minus
}
func main() {
add, minus := f(10, 2)
fmt.Println(add, minus) // 12, 8
}
错误机制
很多内置函数带返回值err
err == nil意味着函数运行成功,non-nil表示失败
五种应对错误的措施
1. 对于内置函数调用错误,向上传播
err直接反给调用者,向上传播
resp, err := http.Get(url)
if err != nil{
return nil, err
}
2. 对于偶然错误,重新尝试
如果错误的发生是偶然性的,或由不可预知的问题导致的。一个明智的选择是重新尝试失败的操作。在重试时,我们需要限制重试的时间间隔或重试的次数,防止无限制的重试。
// WaitForServer attempts to contact the server of a URL.
// It tries for one minute using exponential back-off.
// It reports an error if all attempts fail.
func WaitForServer(url string) error {
const timeout = 1 * time.Minute
deadline := time.Now().Add(timeout)
for tries := 0; time.Now().Before(deadline); tries++ {
_, err := http.Head(url)
if err == nil {
return nil // success
}
log.Printf("server not responding (%s);retrying…", err)
time.Sleep(time.Second << uint(tries)) // exponential back-off
}
return fmt.Errorf("server %s failed to respond after %s", url, timeout)
}
3. 错误发生后程序无法继续运行。则结束程序
输出错误信息并结束程序
// (In function main.)
// 一、
if err := WaitForServer(url); err != nil {
fmt.Fprintf(os.Stderr, "Site is down: %v\n", err)
os.Exit(1)
}