type eface struct {
_type *_type
data unsafe.Pointer
} type iface struct {
tab *itab
data unsafe.Pointer
} var x any = 42 type _type struct {
size uintptr // размер типа в байтах
ptrdata uintptr // размер данных с указателями
hash uint32 // хэш типа
tflag tflag // флаги типа
align uint8 // выравнивание
fieldAlign uint8 // выравнивание полей
kind uint8 // вид типа (int, struct, ptr и т.д.)
// ... и другие поля
} var x any = "hello" x (eface):
┌──────────────┬──────────────┐
│ _type │ data │
├──────────────┼──────────────┤
│ *typeString │ *"hello" │
└──────────────┴──────────────┘
│ │
│ └─────────▶ "hello" (строка в памяти)
│
└────────▶ type metadata для string:
┌─────────────────┐
│ size: 16 │
│ kind: string │
│ ... │
└─────────────────┘ type itab struct {
inter *interfacetype // информация об интерфейсе
_type *_type // информация о конкретном типе
hash uint32 // копия _type.hash для быстрых проверок
_ [4]byte // padding
fun [1]uintptr // таблица методов (переменного размера)
} type Writer interface {
Write(p []byte) (n int, err error)
}
type FileWriter struct {
filename string
}
func (f *FileWriter) Write(p []byte) (n int, err error) {
// реализация записи в файл
return len(p), nil
} var w Writer = &FileWriter{filename: "test.txt"} type Counter struct {
count int
}
func (c Counter) Value() int {
return c.count
}
var i interface{ Value() int } = Counter{count: 5} var i interface{ Value() int } = &Counter{count: 5} var i any = 42
x := i.(int) func describe(i any) {
switch v := i.(type) {
case int:
fmt.Println("int:", v)
case string:
fmt.Println("string:", v)
case bool:
fmt.Println("bool:", v)
}
} var i interface{} = nil // ← Оба поля nil, интерфейс nil
fmt.Println(i == nil) // true var p *int = nil
var i any = p // ← _type указывает на *int, data равен nil
fmt.Println(i == nil) // false! ← Интерфейс не nil i (eface):
┌──────────────┬──────────────┐
│ _type │ data │
├──────────────┼──────────────┤
│ *typeIntPtr │ nil │
└──────────────┴──────────────┘ func getError() error {
var err *MyError = nil
if someCondition {
err = &MyError{message: "something went wrong"}
}
return err // ← Возвращаем nil указатель, но интерфейс не nil!
}
func main() {
err := getError()
if err != nil {
fmt.Println("Error occurred:", err) // ← Выполнится, даже если err nil!
}
} func getError() error {
var err *MyError = nil
if someCondition {
err = &MyError{message: "something went wrong"}
}
if err != nil {
return err
}
return nil // ← Явно возвращаем nil интерфейс
} c := Counter{count: 0}
c.Increment() // ← Компилятор знает адрес метода напрямую var i Incrementer = &Counter{count: 0}
i.Increment() // ← Нужно извлечь адрес из itab func process() {
c := Counter{count: 0} // ← Изначально на стеке
var i Incrementer = &c // ← Теперь "убегает" в кучу
i.Increment()
} go build -gcflags="-m" main.go ./main.go:10:6: moved to heap: c