首先先看一个示例,看看你能否发现代码中的问题。
package main
import "fmt"
func main() {
arr := []string{"hello", "world"}
fmt.Println(test(arr))
}
func test(arr []string) string {
return arr[0]
}
在实际工作中,可能不会写这么简单的代码,但是上面代码的错误在你的代码中有可能会出现。至于上面代码错在哪里,其原因在于当引用一个为nil
的切片时,即使下标为0的元素,也会造成代码出现index out of range
。
package main
import "fmt"
func main() {
arr := []string{"hello", "world"}
fmt.Println(test(arr))
fmt.Println(test(nil))
}
func test(arr []string) string {
return arr[0]
}
执行上述代码,就会触发panic,导致程序不能继续运行。在多层嵌套的函数调用中出现panic,程序会马上中止当前函数的执行,所有的defer语句会把控制权交还给接收到panic的函数调用者。这样向上冒泡直到最顶层,并执行每层的defer,然后在栈顶处程序崩溃。
hello
panic: runtime error: index out of range
goroutine 1 [running]:
main.test(...)
D:/mygo/test.go:12
main.main()
D:/mygo/test.go:8 +0xc0
exit status 2
在实际应用中,这一情况是不允许出现的,即使出现panic,也不能让程序停止运行。可以的做法就是使用recover内建函数,让程序从panic中恢复。其中recover
只能在defer修饰的函数中使用,用于取得panic调用中传递过来的错误值,如果是正常执行,调用recover会返回nil,且没有其他效果。
package main
import "fmt"
func main() {
arr1 := []string{"hello", "world"}
fmt.Println(test(arr1))
defer func() {
if err := recover(); err != nil {
fmt.Printf("panic %s\n", err)
}
}()
fmt.Println(test(nil))
}
func test(arr []string) string {
return arr[0]
}
还有另外一种方法,就是在含有切片参数的函数中,首先对参数进行判断。例如:
package main
import "fmt"
func main() {
arr := []string{"hello", "world"}
fmt.Println(test(arr))
fmt.Println(test(nil))
}
func test(arr []string) string {
if len(arr) != 0 {
return arr[0]
}else {
return "error"
}
}