17、nil指针-GOLANG

通向惊恐的nil指针

golang
1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
var nowhere *int
fmt.Println(nowhere)
//fmt.Println(*nowhere) //针对nil指针的解引用会使程序崩溃
}

保护方法

golang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "fmt"

type person struct {
age int
}

func (p *person) birthday() {
p.age++
}
func main() {
var nobody *person
fmt.Println(nobody)
//nobody.birthday()//造成惊恐导致程序崩溃
}

修改

golang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

type person struct {
age int
}

func (p *person) birthday() {
if p == nil {
return
}
p.age++
}
func main() {
var nobody *person
fmt.Println(nobody)
nobody.birthday() //通过if判断避免程序崩溃
}

nil函数值

golang
1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
var fn func(a, b int) int
fmt.Println(fn == nil)
}

image-20230312083237040

golang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
"sort"
)

func sortStrings(s []string, less func(i, j int) bool) {
if less == nil {
less = func(i, j int) bool {
return s[i] < s[j]
}
sort.Slice(s, less)
}
}
func main() {
food := []string{"onion", "carrot", "celery"}
sortStrings(food, nil)
fmt.Println(food)
}

nil切片

切片在声明之后没有使用复合字面量或者内置的make函数进行初始化,那么值为nil,不过关键字range,len,append等内置函数可以正常处理为nil的切片

golang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main() {
var soup []string
fmt.Println(soup == nil)

for _, value := range soup {
fmt.Println(value)
}
fmt.Println(len(soup))
soup = append(soup, "onion", "carrot", "celery")
fmt.Println(soup)
}

不包含任何元素的空切片和值为nil的切片并不相等,但是通常它们可以替换使用

golang
1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func mirrpoix(ing []string) []string {
return append(ing, "onion", "carrot", "celery")
}

func main() {
soup := mirrpoix(nil)
fmt.Println(soup)
}

nil的其他选择

golang
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
package main

import "fmt"

type number struct {
value int
valid bool
}

func newNumber(v int) number {
return number{value: v, valid: true}
}
func (n number) String() string {
if !n.valid {
return "not set"
}
return fmt.Sprintf("%d", n.value)
}

func main() {
n := newNumber(42)
fmt.Println(n)

e := number{}
fmt.Println(e)
}