es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿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

Tags:  ,

Answer

  1. Avatar for 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 es nil o no en tiempo de ejecución. En este caso, aunque w.foo es nil, el receptor de los métodos level1(), level2() y level3() sigue siendo la estructura Foo, que no es nil ya que forma parte de la estructura FooWrapper. Por lo tanto, cuando se llaman estos métodos, el programa entra en pánico cuando intenta desreferenciar un puntero nil dentro de uno de estos métodos en lugar de entrar en pánico en el punto donde se accede a w.foo.

    Para hacer que el programa entre en pánico en el punto donde se accede a w.foo, los métodos level1(), level2() y level3() se pueden actualizar para incluir una verificación de un puntero nil antes de llamar al siguiente método. Por ejemplo:

    func (f *Foo) level3() {
        if f == nil {
            fmt.Printf("f es nil en el nivel 3\n")
        } else {
            f.level4()
        }
    }
    
    func (f *Foo) level2() {
        if f == nil {
            fmt.Printf("f es nil en el nivel 2\n")
        } else {
            f.level3()
        }
    }
    
    func (f *Foo) level1() {
        if f == nil {
            fmt.Printf("f es nil en el nivel 1\n")
        } else {
            f.level2()
        }
    }
    

    Al agregar estas verificaciones para un puntero nil, el programa ahora entrará en pánico en el punto donde se accede a w.foo en main().

Comments are closed.