Programmer

Will Change The World

方法的receiver为nil的时候是否会造成panic?

以下代码是否会造成程序panic?

package main

import "fmt"

type Table struct {
	name string 
}

func (t *Table) TableName() string {
	return t.name
}

func main() {

	var table *Table

	fmt.Println(table.TableName())

}

毫无疑问,

因为table只是声明了变量,但是没有赋值,此时值为零值nil,在调用对应方法时会造成nil dereference panic。

那下面的代码会panic吗?

package main

import "fmt"

type Table struct {}

func (t *Table) TableName() string {
	return "hello_world"
}

func main() {

	var table *Table

	fmt.Println(table.TableName())

}

答案是,不会

为啥呢?因为TableName方法里,没有访问Table类型的成员变量,因此不涉及解引用,所以不会panic。

其实一个方法(method)等价于第一个参数为receiver的函数(function),例如:

type Table struct {}

func (t *Table) TableName() string {
	return "hello_world"
}

其实等价于

type Table struct {}

func  TableName(t *Table) string {
	return "hello_world"
}

这时候再看,就很明白了,作为参数的时候,t可以为nil吗?可以。会panic吗?不会。因此等价的方法也不会panic。

再一个,真正引起panic的是对nil指针进行解引用操作,如果没有解引用,那么也不会造成panic。解引用就是去寻找一个内存地址对应的真正数据,在找之前会判断地址是否有效,若无效,则就会引起panic。

比如下面的方法:

type Pointer struct{}

func (p *Pointer)PrintAddr() {
	fmt.Sprint("addr: %p", p)
}

// output: addr: 0x0

以上的方法,虽然访问了p,并且p也是nil,但是因为没有解引用,所以没有panic。

那么问题来了,以下的代码会造成panic吗?

package main

import "fmt"

type Table struct {}

func (t Table) TableName() string {
	return "hello_world"
}

func main() {

	var table *Table

	fmt.Println(table.TableName())

}

答案是:会!

这里为啥又会了呢?

按照上面等价理论来说,确实是不会,但是需要注意的一点是,以指针类型去调用非指针类型方法时,是会自动对指针进行解引用的,因此还是会造成panic。用以上等价理论解释就是等价于以下代码:

type Table struct {}

func TableName(t Table) string {
	return "hello_world"
}

func main() {

	var pointer *Table
	table = *pointer
	fmt.Println(TableName(table))

}

真正导致panic的地方是在main中的第二行代码,而并非是在TableName中。

总结,nil receiver是否会造成panic,主要取决于是否对其进行了解引用操作,如果有,则会panic,如果没有,则不会引起panic

点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注