Go语言学习笔记4-函数

函数

func 函数名(参数列表) (返回参数列表) {
函数体
}

  • 带有变量名的返回值
    类似C#中的out,直接在函数体中对返回值进行赋值,函数结束时需要显示的使用return语句进行返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//多返回值
func typedTwoValues() (int, int){
return 1,2
}

x, y := typedTwoValues()

//带有变量名的返回值
func namedRetValues() (a, b int) {
a = 1
b = 2

return
}
  • 函数也是一种类型,可以被保存在变量中
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
stringProccess := func(list []string, chain []func(string) string) {
for index, str := range list{
result := str
for _, proc := range chain{
result = proc(result)
}

list[index] = result
}
}

removePrefix := func(s string) string{
return strings.TrimPrefix(str, "go")
}

handleList := []string{
"go scanner",
"go parser",
"go compiler"
}

handleChain := []func (string) string{
removePrefix,
strings.TrimSpace,
strings.ToUpper,
}

stringProccess(handleList, handleChain)
  • 闭包
    闭包是引用了自由变量的函数,被引用的自由变量和函数一同存在
    被捕获到闭包的变量让闭包本身拥有了记忆效应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"fmt"
)

func playerGen(name string) func() (string, int) {
hp := 150

return func() (string, int) {
return name, hp
}
}

func main() {
generator := playerGen("high noon")
name, hp := generator()
fmt.Println(name, hp)
}
  • 可变参数

func 函数名(固定参数列表, v …T) (返回参数列表){
函数体
}

  1. 可变参数一般放置在函数参数列表的末尾,前面是固定参数列表,当没有固定参数时,所有变量将是可变参数
  2. 可变参数变量为一个拥有多个T元素的T类型切片
  3. T为interface{}时,传入的可以是任意类型
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
package main

import (
"bytes"
"fmt"
)

func main() {
fmt.Println(convertFunc(100,"str", true))
}

func printTypeValue(slist ...interface{}) string {
var b bytes.Buffer

for _, s := range slist {
str := fmt.Sprintf("%v", s)

var typeString string

switch s.(type) {
case bool:
typeString = "bool"
case string:
typeString = "string"
case int:
typeString = "int"
}

b.WriteString("value::")
b.WriteString(str)
b.WriteString(" type: ")
b.WriteString(typeString)
b.WriteString("\n")
}
return b.String()
}

//传递可变参数时,在可变参数中添加"...",可以将切片中的元素进行传递,而不是传递可变参数变量本身
func convertFunc(slist ...interface{}) string {
return printTypeValue(slist...)
}
  • defer
    在defer归属的函数即将返回时,将延迟处理的语句按defer的逆序进行执行
1
2
3
4
5
6
7
8
9
10
11
12
var (
valueByKey = make(map[string]int)
valueByKeyGuard sync.Mutex
)

func readValue(key string) int {
valueByKeyGuard.Lock()
//延迟到函数结束时调用
defer valueByKeyGuard.Unlock()

return valueByKey[key]
}
  • error
    自定义错误可以通过自定义结构体实现错误接口来实现
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
type ParseError struct {
Filename string
Line int
}

//实现错误接口
func (e *ParseError) Error() string {
return fmt.Sprintf("%s:%d", e.Filename, e.Line)
}

func newParseError(filename string, line int) error {
return &ParseError{filename, line}
}

func main() {
var e error
e = newParseError("main.go", 1)

fmt.Println(e.Error())

switch detail := e.(type) {
case *ParseError:
fmt.Printf("Filename: %s Line: %d\n", detail.Filename, detail.Line)
default:
fmt.Println("other error")
}
}
  • panic、recover
    手动触发宕机,让程序崩溃,可以及时的发现错误
    当发生崩溃时,可以配合defer和recover实现错误捕捉和恢复,类似C#中的try/catch
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
package main

import (
"fmt"
"runtime"
)

type PanicContext struct {
function string
}

func ProtectRun(entry func()) {
defer func() {
err := recover()

switch err.(type) {
case runtime.Error:
fmt.Println("runtime error:", err)
default:
fmt.Println("error:", err)
}
}()

entry()
}

func main() {
ProtectRun(func() {
panic(&PanicContext{"手动触发panic"})
})

ProtectRun(func() {
//模拟空指针赋值造成的错误
var a *int
*a = 1

//函数会在这之前退出后继续执行
fmt.Println("赋值宕机后")
})
}
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2021 Azella
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信