Почему Go набрал нуль?

Почему Go набрал nil? Он упрощает явную проверку конфигурации интерфейса. Какая проблема нетипизированного nil и что дизайнеры хотели решить с помощью напечатанных nil?

Ответ 1

Похоже, вы спрашиваете об этом сообщении об ошибке:

http://play.golang.org/p/h80rmDYCTI

package main

import "fmt"

type A struct {}
type B struct {}

func (a *A) Foo() {
    fmt.Println("A")
}

func (b *B) Foo() {
    fmt.Println("B")
}

func main() {
    n := nil
    n.Foo()
}

Отпечатки:

prog.go:17: use of untyped nil
 [process exited with non-zero status]

В этом примере, должна ли программа печатать "A" или "B"?

Вы должны помочь компилятору решить. Как вы это делаете, указав тип n.

Например:

http://play.golang.org/p/zMxUFYgxpy

func main() {
    var n *A
    n.Foo()
}

печатает "A".

В других языках n.Foo() может немедленно сработать, если n - nil или его эквивалент. Дизайнеры языка "Go" решили позволить вам определить, что должно произойти вместо этого. Если вы обращаетесь к указателю без проверки на nil, вы получите то же поведение, что и на других языках.

Ответ 2

Это связано с типом безопасности. nil фактически является значением неинициализированных переменных в Go. Значения nil для срезов, карт, функций, каналов, указателей и интерфейсов не одного типа и не сопоставимы. Подробнее читайте в спецификации языка.

ОБНОВЛЕНИЕ: Как указано @newacct, правильным техническим термином для этого является "нулевое значение" для типа:

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

Пример детской площадки

Также есть некоторая информация о nil-интерфейсах и ошибках на Почему значение моей ошибки nil не равно nil? в Go FAQ.

Ответ 3

Все переменные в Голанге должны иметь тип. Использование := оператор выводит тип из типа выражения справа.

x := [0]int{}       // var x [0]int
y := make(chan int) // var y chan int
z := map[int]int{}  // var z map[int]int
a := func(int) {}   // var a func(int)
b := 42             // var b int
c := 42.0           // var c float64

Для почти любого выражения его тип недвусмыслен, из-за необходимости явно указывать тип где-то - или в случае числовых литералов, имеющих значение по умолчанию при неопределенности. Единственным исключением из этого правила является nil.

n := nil // var n ???

nil является допустимым значением для следующего.

  • указатели
  • Небезопасные указатели
  • Интерфейсы
  • каналы
  • Карты
  • Ломтики
  • функции

Не существует хорошего значения по умолчанию для типа, когда пользователь вводит nil, поэтому вместо этого Golang отклоняет это требование, требующее явной спецификации типа.

Ответ 4

Без ввода nil вы не можете использовать оператор короткого присваивания := со значением nil.

a := nil // Error: use of untyped nil
b := error(nil) // OK

Он также включает следующую однострочную строку:

result, err := "A good result", error(nil)

Написание чего-либо подобного может иногда оказаться удобным.


Однако обратите внимание, что nil не является ключевым словом или литералом - и Go не имеет встроенного или стандартного значения typed-nil. Typed-nil существует только в результате одного из следующих действий:

  • объявление переменной типа nillable с инициализацией по умолчанию ("нулевое значение")
  • присвоение nil (прямо или косвенно) типизированному значению
  • приведение идентификатора nil к типу (как показано в примерах выше).

Вот клип о тонкостях с набранными нулями и интерфейсами: GopherCon 2015: Кевин Кэнтвелл - Что может пойти не так?