Можно ли определить равенство для именованных типов/структур?

После прочтения связанного вопроса об использовании фрагментов на картах мне стало интересно узнать о равенстве в Go.

Я знаю, что можно переопределить метод equals Java Object. Есть ли аналогичный способ определить, как Go проверяет определенные пользователем типы/структуры для равенства? Если это так, было бы обходным путем для проблемы, упомянутой выше. Я думал, что использование interface{} values ​​ может предложить решение, но я получил сообщение об ошибке panic: runtime error: hash of unhashable type []int.

Ответ 1

Go поддерживает структуры проверки равенства.

type Person struct {
    Name string
}

a := Person{"Bill DeRose"}
b := Person{"Bill DeRose"}

a == b // true

Он не будет работать с полями указателя (так, как вы хотите), потому что адреса указателей отличаются.

type Person struct {
    Friend *Person
}

a := Person{Friend: &Person{}}
b := Person{Friend: &Person{}}

a == b // false

Вы не можете изменить оператор равенства, и нет встроенного способа добавления поддержки для настраиваемых типов для использования синтаксиса ==. Вместо этого вы должны сравнить значения указателя с помощью reflect.DeepEqual.

import "reflect"

a := Person{Friend: &Person{}}
b := Person{Friend: &Person{}}

reflect.DeepEqual(a, b) // true

Имейте в виду, что есть оговорки.

В общем случае DeepEqual является рекурсивной релаксацией оператора Go ==. Однако эту идею невозможно реализовать без некоторой несогласованности. В частности, возможно, чтобы значение было неравным с самим собой, либо потому, что оно имеет тип func (несравнимый вообще), либо потому, что это значение NaN с плавающей запятой (не равное самому себе в сравнении с плавающей запятой), либо потому, что это массив, структура или интерфейс, содержащие такое значение.

Ответ 2

Нет, это не определяется пользователем. Go имеет строгие правила, что считается равным, и даже то, что сопоставимо, которое само основано на назначаемости. Посмотрите раздел операторов сравнения спецификации.