Go 陷阱之 nil 参数

概述 #

nil 可以作为函数参数传入,这意味着函数内部逻辑处理时,不能依赖于传入的实参 (有可能是 nil), 一定要做必要的 零值 判断。

例子 #

示例代码只是为了演示,没有任何实际意义。

参数类型为切片 #

切片nil 时,直接读取和赋值都会 panic

错误的做法 #

package main

// 计算前 N 个数总和
func sumTopN(numbers []int, n int) int {
	total := 0
	for _, v := range numbers[:n] {
		total += v
	}

	return total
}

func main() {
	println(sumTopN(nil, 3))
}

// $ go run main.go
// 输出如下
/**
  panic: runtime error: slice bounds out of range [:3] with capacity 0

  goroutine 1 [running]:
  ...
  ...

  exit status 2

*/

正确的做法 #

package main

// 计算前 N 个数总和
func sumTopN(numbers []int, n int) int {
	// 首先检测参数是否为 nil
	if n > len(numbers) {
		n = len(numbers)
	}

	total := 0
	for _, v := range numbers[:n] {
		total += v
	}

	return total
}

func main() {
	println(sumTopN(nil, 3))
}

// $ go run main.go
// 输出如下 
/**
  0
*/

参数类型为 map #

mapnil 时,直接赋值会 panic

错误的做法 #

package main

// 将目标字符串计数重置为 0
func reset(counter map[string]int, target []string) {
	for _, s := range target {
		counter[s] = 0
	}
}

func main() {
	reset(nil, []string{"hello", "world"})
}

// $ go run main.go
// 输出如下
/**
  panic: assignment to entry in nil map

  goroutine 1 [running]:
  ...
  ...

  exit status 2

*/

正确的做法 #

package main

// 将目标字符串计数重置为 0
func reset(counter map[string]int, target []string) {
	// 首先检测参数是否为 nil
	if counter == nil {
		return
	}
	for _, s := range target {
		counter[s] = 0
	}
}

func main() {
	reset(nil, []string{"hello", "world"})
}

参数类型为指针 #

指针nil 时,直接读取和赋值都会 panic

错误的做法 #

package main

import "fmt"

type person struct {
	name string
}

func setHi(p *person) {
	fmt.Printf("Hi, I'm %s", p.name)
}

func main() {
	setHi(nil)
}

// $ go run main.go
// 输出如下
/**
  panic: runtime error: invalid memory address or nil pointer dereference

  goroutine 1 [running]:
  ...
  ...

  exit status 2

*/

正确的做法 #

package main

import "fmt"

type person struct {
	name string
}

func setHi(p *person) {
	// 首先检测参数是否为 nil
	if p != nil {
		fmt.Printf("Hi, I'm %s", p.name)
	}
}

func main() {
	setHi(nil)
}

代码的首要目标是正确性。

转载申请

本作品采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,商业转载请联系作者获得授权。

© 蛮荆 | 陕公网安备 61011302001681 号 | 陕ICP备2023004378号-1 | Rendered by Hugo