Ответ
Сравнение интерфейсов в Go — это важная концепция, которая проверяет как динамический тип, так и динамическое значение, хранящиеся в интерфейсе.
Правила сравнения
Два интерфейсных значения равны, если выполняется одно из условий:
- Оба интерфейса равны
nil
. - Их динамические типы идентичны, и их динамические значения равны в соответствии с правилами сравнения для этого типа.
Интерфейсы не равны, если:
- Один из них
nil
, а другой нет. - Их динамические типы различаются.
- Их типы одинаковы, но значения не равны.
Пример сравнения
var a, b interface{}
a = 100
b = 100
fmt.Println(a == b) // true (типы int, значения 100 == 100)
b = int64(100)
fmt.Println(a == b) // false (типы разные: int != int64)
var c interface{} = "hello"
var d interface{} = "hello"
fmt.Println(c == d) // true (типы string, значения равны)
⚠️ Паника при сравнении несравниваемых типов
Попытка сравнить два интерфейса, которые содержат значения несравниваемых типов, вызовет панику во время выполнения.
К несравниваемым типам относятся:
- Слайсы (
slice
) - Карты (
map
) - Функции (
func
)
var c interface{} = []int{1, 2}
var d interface{} = []int{1, 2}
// fmt.Println(c == d) // паника: runtime error: comparing uncomparable type []int
Классическая ловушка: nil
интерфейс vs интерфейс с nil
значением
Интерфейс не равен nil
, если в нем хранится значение, даже если само это значение является nil
-указателем. Это происходит потому, что у такого интерфейса есть динамический тип.
type MyError struct{}
func (e *MyError) Error() string { return "error" }
func getError() error {
var err *MyError = nil // Создаем nil-указатель на структуру
return err // Возвращаем его как интерфейс error
}
func main() {
err := getError()
// err не равен nil, т.к. он содержит тип (*MyError) и значение (nil)
if err != nil {
fmt.Printf("Ошибка! Тип: %T, Значение: %vn", err, err)
}
}
// Вывод:
// Ошибка! Тип: *main.MyError, Значение: <nil>