Как избежать ошибок «неверный адрес памяти или разыменование нулевого указателя»? - PullRequest
2 голосов
/ 27 февраля 2012

Мне интересно, как я могу структурировать этот пример кода, чтобы избежать паники разыменования нулевого указателя:

package main

import "fmt"

type Astruct struct {
    Number int
    Letter string
}

type Bstruct struct {
    foo int
    AStructList *[]Astruct
}

type Cstruct struct {
    Bstruct
}

func (a *Astruct) String() string {
    return fmt.Sprintf("Number = %d, Letter = %s", a.Number, a.Letter)
}

func main() {
    astructlist := make([]Astruct, 3)      // line 1
    for i := range astructlist {           // line 2
        astructlist[i] = Astruct{i, "a"}   // line 3
    }                                      // line 4
    c := new(Cstruct)
    c.Bstruct = Bstruct{100, &astructlist} // line 6

    for _, x := range(*c.Bstruct.AStructList) {
        fmt.Printf("%s\n", &x)
    }
}

Если я опущу строки 1-4 и 6 функции main (), я получаю панику разыменования нулевого указателя. Если не считать проверки c! = Nil, есть ли способ избежать этой паники?

Заранее спасибо за любую помощь!

1 Ответ

6 голосов
/ 27 февраля 2012

В этом конкретном случае вы можете использовать идиоматический Go. Измените AStructList *[]Astruct на AStructList []*Astruct. Например,

package main

import "fmt"

type Astruct struct {
    Number int
    Letter string
}

type Bstruct struct {
    foo         int
    AStructList []*Astruct
}

type Cstruct struct {
    Bstruct
}

func (a *Astruct) String() string {
    return fmt.Sprintf("Number = %d, Letter = %s", a.Number, a.Letter)
}

func main() {
    astructlist := make([]*Astruct, 3)            // line 1
    for i := range astructlist {                  // line 2
        astructlist[i] = &Astruct{i, "a"}         // line 3 
    }                                             // line 4
    c := new(Cstruct)
    c.Bstruct = Bstruct{100, astructlist}         // line 6

    for _, x := range c.Bstruct.AStructList {
        fmt.Printf("%s\n", x)
    }
}

В целом, вы обязаны либо присвоить не nil значение указателю, либо проверить значение nil перед его использованием. Когда вы выделяете память без явного ее инициализации, для типа устанавливается нулевое значение, для указателей это nil.

Нулевое значение

Когда память выделяется для хранения значения, либо через объявление или вызов make или new, без явной инициализации при условии, памяти дается инициализация по умолчанию. каждый элементу такого значения присваивается нулевое значение для его типа: false для логических значений, 0 для целых чисел, 0,0 для чисел с плавающей запятой, "" для строк и ноль для указателей, функций, интерфейсов, срезов, каналов и карт. это инициализация выполняется рекурсивно, поэтому, например, каждый элемент массив структур будет обнулять свои поля, если не указано значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...