Как правильно проверить нулевую ссылку на указатель? - PullRequest
0 голосов
/ 22 декабря 2019

Чтобы проиллюстрировать вопрос:

Скажем, у вас есть следующая структура с методом display (получателем значения), предназначенным для печати содержимого:

type ListNode struct {
    Val  int
    Next *ListNode
}


func (l ListNode) display() {
    for &l != nil {
        fmt.Printf("%v ->", l.Val)
        l = *l.Next
    }
    fmt.Println()
}

func main() {
    num1 := ListNode{2, &ListNode{4, &ListNode{3, nil}}}

    num1.display()
}

Вышеуказанное выполнениепроизойдет ошибка в последнем цикле, поскольку я попытался отменить ссылку на ноль с помощью этого вывода:

2 ->4 ->3 ->panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x109ae6f]

Однако, изменяя функцию на приемник указателя, она элегантно становится:

func (l *ListNode) display() {
    for l != nil {
        fmt.Printf("%v ->", l.Val)
        l = l.Next
    }
    fmt.Println()
}

со счастливым выводом:

2 ->4 ->3 ->

Будучи «новичком», я решил, что поскольку функция display() предназначена только для чтения, было бы лучше написать функцию с получателем значения,но столкнуться с этим вопросом. Есть ли более изящное решение с отсутствующим приемником значений или лучший способ отменить ссылку в исходной функции?

Ответы [ 3 ]

3 голосов
/ 22 декабря 2019

Нет смысла проверять адрес получателя значения, чтобы увидеть, равен ли он нулю следующим образом:

 for &l != nil {

Здесь l - это переменная со значением, и она никогда не может бытьноль.

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

func (l *ListNode) display() {
   for trc:=l; trc!=nil; trc=trc.Next {
        fmt.Printf("%v ->", trc.Val)
    }
}

Если вы получите получатель значения:

func (l ListNode) display() {
   for trc:=&l; trc!=nil; trc=trc.Next {
        fmt.Printf("%v ->", trc.Val)
    }
}
2 голосов
/ 22 декабря 2019

Тот факт, что у вас есть получатель значения, не меняет того факта, что у вас есть поля указателя. И вам не нужно приводить их форму к форме получателя (значение / указатель). Они могут оставаться указателями. Нет необходимости в разыменовании (явно).

func (l ListNode) display() {
    curNode := &l
    for curNode != nil {
        fmt.Printf("%v ->", curNode.Val)
        curNode = curNode.Next
    }
    fmt.Println()
}
0 голосов
/ 22 декабря 2019

Это сдерживание указателя:

v = *ptr

Это приведет к сбою, если ptr равен нулю. Вы проверяете на ноль до разыменования.

if ptr != nil {
    v = *ptr
    // ...... 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...