¿Por qué ocurre la desreferencia de puntero nulo en los submétodos de Golang?
Tengo este código
paquete principal
import "fmt"
type Foo struct {
Bar string
}
func (f *Foo) level4() {
fmt.Printf("Bar = %s\n", f.Bar)
}
func (f *Foo) level3() {
f.level4() // ocurre el error aquí, 2 niveles abajo
}
func (f *Foo) level2() {
f.level3()
}
func (f *Foo) level1() {
f.level2()
}
type FooWrapper struct {
foo *Foo
}
func main() {
w := FooWrapper{}
w.foo.level1() // se esperaba que ocurra un error aquí, ya que foo es nil
}
Así como se esperaba, al ejecutar esto se obtiene
panic: error en tiempo de ejecución: dirección de memoria no válida o declaración de puntero nulo
[signal SIGSEGV: violación de segmento código=0x1 addr=0x0 pc=0x47f454]
Sin embargo, esperaba que la declaración de puntero nulo ocurriera en w.foo.level1()
, ya que foo
es nil
. En cambio, se llaman a los niveles 1, 2 y 3 y ocurre el error allí. ¿Por qué ocurre esto?
Enlace al playground: playground link
davy.ai
La razón por la que se produce el pánico en los niveles 1, 2 y 3 en lugar de
w.foo.level1()
es porque Go verifica si el receptor de un método esnil
o no en tiempo de ejecución. En este caso, aunquew.foo
esnil
, el receptor de los métodoslevel1()
,level2()
ylevel3()
sigue siendo la estructuraFoo
, que no esnil
ya que forma parte de la estructuraFooWrapper
. Por lo tanto, cuando se llaman estos métodos, el programa entra en pánico cuando intenta desreferenciar un punteronil
dentro de uno de estos métodos en lugar de entrar en pánico en el punto donde se accede aw.foo
.Para hacer que el programa entre en pánico en el punto donde se accede a
w.foo
, los métodoslevel1()
,level2()
ylevel3()
se pueden actualizar para incluir una verificación de un punteronil
antes de llamar al siguiente método. Por ejemplo:Al agregar estas verificaciones para un puntero
nil
, el programa ahora entrará en pánico en el punto donde se accede aw.foo
enmain()
.