Почему Go набрал nil
? Он упрощает явную проверку конфигурации интерфейса. Какая проблема нетипизированного nil
и что дизайнеры хотели решить с помощью напечатанных nil
?
Почему Go набрал нуль?
Ответ 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: Кевин Кэнтвелл - Что может пойти не так?