G
go-with-me
@golangwithus1.9K подп.
2.9Kпросмотров
22 июля 2025 г.
📷 ФотоScore: 3.2K
🎨 Interface Comparisons В этот раз поговорим про сравнения интерфейсов и развеем все мифы, которые вы могли встретить на своем пути Нюансы в этой теме важны для понимания ввиду возможности паник при использовании некорректных нижележащих сущностей Для начала взглянем на структуру не пустого интерфейса: type iface struct { tab *itab data unsafe.Pointer } — С полем data все прозрачно - это непосредственно те данные, которые мы закладываем при присваивании интерфейсу какого-то значения — itab содержит метаданные об интерфейсе, о реализующем его типе и методах Ключевое: при сравнении не пустых интерфейсов мы сравниваем две структуры iface: itab и data. В случае с пустыми интерфейсами eface сравниваем не itab, а сам тип _type Приступим к рассмотрению боевых примеров! 1. Сравнение простых композитных типов В данном случае все достаточно тривиально, itab одинаковы и, следовательно можем приступить к сравнению data, а они как раз являются разнымии. Смело получаем false и идем дальше func A() { var v1, v2 any p1 := Person{ Name: "Bob", Age: 18, } p2 := Person{ Name: "John", Age: 19, } v1, v2 = p1, p2 fmt.Println(v1 == v2) } 2. Несравнимые типы Первое, что необходимо зарубить себе на носу - такие сущности как map, slice, func являются uncomparable. При попытке сравнить таковые мы моментально получаем panic и идем в люльку (в близлежащий defer) Go Playground (тык) 3. Композитные типы с вложенными несравнимыми сущностями Нос мы свой не щадим и зарубаем еще одну штуку - несравнимый тип, содержащийся в структуре, аффектит сравнение всей структуры. Иначе говоря, все поля структуры (включая вложенные) должны быть сравнимыми type UncomparablePerson struct { Name string Age uint8 Pets []string Things map[string]struct{} Action func() } 3.1 Различные типы и вложенно несравнимые сущности Мы дошли до нетривиального случая. Имеем следующий расклад: — Наши _type разные, ввиду того, что типы разные — Один из типов вложенно хранит в себе множество несравнимых типов Наивным предположением было бы думать, что мы словим панику, но как бы не так! Сравнение двух структур (eface или iface) происходит линейно (как и с массивами): сначала сравниваются поля (tab или _type), потом data. Так как типы у нас разные, поэтому сравнения полей data не будет Получаем заслуженный false и идем дальше! func C() { var v1, v2 any p := Person{ Name: "Bob", Age: 18, } up := UncomparablePerson{ Name: "John", Age: 21, Pets: nil, Things: map[string]struct{}{ "ball": {}, }, } up.Action = func() { fmt.Printf("My age is %s\n", up.Name) } v1, v2 = p, up fmt.Println(v1 == v2) // false } 3.2. Одинаковые типы и вложенно несравнимые сущности Комментарий с выводом говорит сам за себя. Типы одинаковые, data содержит несравнимые сущности, получаем panic. Все тривиально Go Playground(тык) 4. Сравнение интерфейса напрямую с неинтерфейсным значением Мало тех, кто знает о том, что можно сравнить переменную интерфейса напрямую с каким-то значением. Происходить все будет аналогично сравнению двух интерфейсов func E() { var v1 any p1 := Person{ Name: "A", Age: 12, } v1 = p1 fmt.Println(v1 == p1) } 5. Алиасы и новые типы в интерфейсах Напоминание о том, как работают синонимы и типовые переопределения type ( AliasedInteger = int // Синоним (type alias) для int:идентичен int, взаимозаменяем с ним AnotherInteger int // Новый тип на базе int: не совместим с int напрямую, но имеет ту же внутреннюю структуру ) func F() { var v1, v2 any i, ai, ali := 1, AnotherInteger(1), AliasedInteger(1) v1, v2 = i, ali fmt.Println(v1 == v2) // true v1, v2 = i, ai fmt.Println(v1 == v2) // false castAiToInt := int(ai) v1, v2 = i, castAiToInt fmt.Println(v1 == v2) // true } Надеемся, что материал для вас был полезным. Если возникли какие-ни
2.9K
просмотров
4000
символов
Нет
эмодзи
Да
медиа

Другие посты @golangwithus

Все посты канала →
🎨 Interface Comparisons В этот раз поговорим про сравнения — @golangwithus | PostSniper