函数
函数声明
1
2
|
func f(i, j, k int, s, t string) { /* ... */ }
func f(i int, j int, k int, s string, t string) { /* ... */ }
|
函数签名
函数的类型被称为函数的签名。如果两个函数形式参数列表和返回值列表中的变量类型一一对应,那么这两个函数被认为有相同的类型或签名。
函数返回值
返回的是值类型变量, 分配在栈上, 返回的是引用类型分配在堆上, 当不再需要时, gc 自动回收
如果一个函数所有的返回值都有显式的变量名,那么该函数的return语句可以省略操作数。这称之为bare return。
这样会使代码不易理解 , 不宜过度使用
1
2
3
4
|
func sub(x, y int) (z int) {
z = x - y;
return // 此处等价于 return z
}
|
实参通过值的方式传递,包括引用类型, 也是值传递 , 因此函数的形参是实参的拷贝。
如果实参是引用类型,如指针,slice(切片)、map、function、channel等类型,实参可能会由于函数的间接引用被修改。
可能会偶尔遇到没有函数体的函数声明,这表示该函数不是以Go实现的。
递归
golang.org/x/net/html
html.Parse函数读入一组bytes解析后,返回html.Node类型的HTML页面树状结构根节点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
doc, _ := html.Parse(os.Stdin)
visit(nil, doc)
func visit(links []string, n *html.Node) []string {
if n.Type == html.ElementNode && n.Data == "a" {
for _, a := range n.Attr {
if a.Key == "href" {
links = append(links, a.Val)
}
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
links = visit(links, c)
}
return links
}
|
多返回值
1
2
3
|
links, err := findLinks(url)
// 也可以使用 - 忽略
_, err := findLinks(url)
|
有些预料中的错误 , 会作为函数的第二个返回值 , 可以使用 fmt.Errorf('%v',err)
封装错误, 使用 Unwrap
来获取上一层的错误
函数是一等公民
函数可以赋值 , 有类型
函数的零值是 nil
, 调用零值函数会引起 panic 异常
函数值可以与 nil
比较, 但是不能相互比较 , 且不能作为 map 的 key
strings.Map对字符串中的每个字符调用add1函数,并将每个add1函数的返回值组成一个新的字符串返回给调用者。
1
2
3
4
5
|
func add1(r rune) rune { return r + 1 }
fmt.Println(strings.Map(add1, "HAL-9000")) // "IBM.:111"
fmt.Println(strings.Map(add1, "VMS")) // "WNT"
fmt.Println(strings.Map(add1, "Admix")) // "Benjy"
|
匿名函数
1
|
strings.Map(func(r rune) rune { return r + 1 }, "HAL-9000")
|
闭包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
func squares() func() int {
var x int
return func() int {
x++
return x * x
}
}
func TestSquares(t *testing.T) {
f := squares()
fmt.Println(f()) // "1"
fmt.Println(f()) // "4"
fmt.Println(f()) // "9"
fmt.Println(f()) // "16"
}
|
可变参数列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// 多返回值 这里的函数返回值 (q,r int) <=> (int,int)
func returnDoubleValue(a,b int) (q, r int){
return a/b,a*b
}
q, _ := returnDoubleValue(3,9)
// 函数为形参, 也可以返回函数
func apply(op func(int,int) int, a,b int) int {
return op(a,b)
}
/// ... 可变参数列表
func sum(numbers ...int) int {
s := 0
for i:= range numbers {
s += numbers[i]
}
return s
}
fmt.Println(sum(1,2,3,4,5))
|
main 函数
- 必须是 main 包
- 必须是 main 方法
- 文件名不一定是 main.go
- Go 中 main 函数不支持任何返回值
- 通过 os.Exit 来返回状态, 返回的值 范围 -1 ~ 255 ,除了 0 , 其余状态码都是 1
- 在程序中直接通过 os.Args 获取命令行参数