MiddleКодИногдаЕщё не отвечали
Что выведет эта программа с typed-nil интерфейсом и двумя утверждениями типа?
Прочитайте фрагмент ниже. Пустому интерфейсу i присваивается nil-указатель *Type, затем он проверяется через == nil и через утверждение типа i.(*Type).
Определите, какие именно строки и в каком порядке выведет программа, и объясните исход каждой ветви.
type Interface interface{}
type Type struct{}
func main() {
var i Interface
if i == nil {
fmt.Println("i is nil")
}
var t *Type
i = t
if i == nil {
fmt.Println("i is nil")
}
if i.(*Type) == nil {
fmt.Println("i value is nil")
}
t = &Type{}
i = t
if i.(*Type) == nil {
fmt.Println("i value is nil")
}
}
Определите вывод.
Печатает i is nil, затем i value is nil — две строки. После i = t, где t — nil *Type, интерфейс хранит слово типа *Type и nil-данные, поэтому i == nil ложно и эта ветвь пропускается. Но i.(*Type) извлекает сам указатель, который nil, поэтому сравнение истинно. После t = &Type{} указатель не nil, и последняя ветвь пропускается.
- ✗Ждать, что второе
i == nilистинно, раз хранимый указатель nil - ✗Думать, что
i.(*Type)заново оборачивает nil и потому паникует, а не выдаёт nil-указатель - ✗Путать
i == nil(сравнивает весь интерфейс) иi.(*Type) == nil(сравнивает извлечённый указатель)
- →Сработала бы вторая ветвь, будь
tобъявлен какInterface, а не*Type? - →Что сделает
i.(*Type), если в этот момент интерфейс хранит другой конкретный тип?
Оглавление
Код
package main
import "fmt"
type Interface interface{}
type Type struct{}
func main() {
var i Interface
if i == nil {
fmt.Println("i is nil") // печатается: i ещё пустой интерфейс
}
var t *Type
i = t // i хранит (тип=*Type, данные=nil) → typed nil
if i == nil {
fmt.Println("i is nil") // НЕ печатается: слово типа != nil
}
if i.(*Type) == nil {
fmt.Println("i value is nil") // печатается: извлечённый указатель = nil
}
t = &Type{}
i = t
if i.(*Type) == nil {
fmt.Println("i value is nil") // НЕ печатается: указатель уже не nil
}
}
Вывод
i is nil
i value is nil
Ключевая идея — отличать сравнение всего интерфейса от сравнения извлечённого указателя:
i == nilистинно только когда оба слова интерфейса (тип и данные) нулевые. Присваивание nil-указателя*Typeставит слово типа в*Type, поэтому интерфейс становится non-nil — это «typed nil».i.(*Type)извлекает динамическое значение — сам указатель*Type. Здесь он nil, поэтомуi.(*Type) == nilистинно. Это сравнивает указатель, а не интерфейс.- После
t = &Type{}указатель не nil, поэтому последняя ветвь пропускается.
Оглавление