11.函数

函数

函数声明

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 函数

  1. 必须是 main 包
  2. 必须是 main 方法
  3. 文件名不一定是 main.go
  4. Go 中 main 函数不支持任何返回值
  5. 通过 os.Exit 来返回状态, 返回的值 范围 -1 ~ 255 ,除了 0 , 其余状态码都是 1
  6. 在程序中直接通过 os.Args 获取命令行参数
Licensed under CC BY-NC-SA 4.0
本文阅读量 次, 总访问量 ,总访客数
Built with Hugo .   Theme Stack designed by Jimmy