Вызов функции для элемента структуры, который является нулевым указателем - PullRequest
1 голос
/ 09 марта 2019

Однако в Go функция, вызываемая синтаксисом Expression.Name(), полностью определяется типом выражения, а не конкретным значением времени выполнения этого выражения, включая nil - copyied

Таким образом, мы можем вызвать method, используя экземпляр структуры, который равен nil.

Рассмотрим следующую программу:

 package main

    import "fmt"

    type T struct {
        V int
        tt *T
    }

    func (t *T) hello() string {
       return "world"
   } 

    func main() {
        var t *T = nil
        fmt.Println(t, t.hello()) // <nil> world
        fmt.Println(t, t.tt.hello()) // panic
    }

Почему fmt.Println(t, t.hello()) сработал?

Но

fmt.Println(t, t.tt.hello()) запаниковал ?.

Насколько я понимаю, t и t.tt являются nil указателями.Так что t.tt.hello() не должно паниковать, так как в golang разрешен вызов метода с указателем структуры nil.

Ответы [ 4 ]

3 голосов
/ 09 марта 2019

Точнее говоря, t - нулевой указатель, а t.tt вообще не существует.Паника, которую вы видите, является результатом разыменования t, а не t.tt.Это просто скрыто тем фактом, что t.tt является (или будет, если t был инициализирован) также указателем.

Это можно сделать более понятным, открыв поле V в t:

func (t *T) foo() {
    fmt.Println(t.V) // Will panic, if `t` is nil
}

Причина, по которой первый тест не паникует, состоит в том, что вызов метода на t фактически не разыменовывает t.Вызов t.Hello() примерно эквивалентен вызову Hello(t), поэтому не будет паниковать, если только / 101 * не будет фактически разыменована внутри функции.

2 голосов
/ 09 марта 2019

t ноль, нет t.tt.

И t.hello() похоже на hello(t), hello(nil) не паникуйте, но t.tt делайте.

Помните: метод - это просто функция с аргументом получателя.

Выражения метода

2 голосов
/ 09 марта 2019

Насколько я понимаю, и t, и t.tt являются нулевыми указателями.Так что t.tt.hello () не должен паниковать, так как в golang разрешен вызов метода по указателю структуры nil.

Ваше "понимание" неверно. t.tt должно и panic.


Go 1.2 Примечания к выпуску (декабрь 2013 г.)

Использование nil

Языктеперь указывает, что по соображениям безопасности определенное использование нулевых указателей гарантированно вызовет панику во время выполнения.Например, в Go 1.0 для данного кода типа

type T struct {
    X [1<<24]byte
    Field int32
}

func main() {
    var x *T
    ...
}

нулевой указатель x может использоваться для неправильного доступа к памяти: выражение x.Field может обращаться к памяти по адресу 1 << 24.Чтобы предотвратить такое небезопасное поведение, в Go 1.2 компиляторы теперь гарантируют, что любая косвенность через указатель nil, как показано здесь, но также и в указателях nil на массивы, значения интерфейса nil, срезы nil и т. Д., Будет паниковать или возвращатьправильное, безопасное ненулевое значение.Короче говоря, любое выражение, которое явно или неявно требует оценки нулевого адреса, является ошибкой.Реализация может внедрить дополнительные тесты в скомпилированную программу для реализации этого поведения. </p>

Более подробная информация содержится в проектном документе .


Короче говоря, любое выражение, которое явно или неявно требует оценки нулевого адреса, является ошибкой.

Следовательно, ожидается следующее поведение.Переадресация для t.tt через nil значение t завершается ошибкой с panic.

package main

import "fmt"

type T struct {
    V  int
    tt *T
}

func (t *T) hello() string {
    return "world"
}

type A struct {
    a int
}

func main() {
    var t *T = nil
    fmt.Println(t)            // nil
    fmt.Println(t.tt.hello()) // panic
}

Playground: https://play.golang.org/p/Szwx5MqNHkQ

Выход:

<nil>
panic: runtime error: invalid memory address or nil pointer dereference
main.main()
    /tmp/sandbox136049644/main.go:21 +0x84
0 голосов
/ 09 марта 2019

nil - нулевое значение для указателей

// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

Источник: https://golang.org/src/builtin/builtin.go?h=nil#L101

Чтобы понять nil это фантастическое видео
https://www.youtube.com/watch?v=ynoY2xz-F8s

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