Мне интересно, в каких случаях тесты равенства в F # вызывают бокс, и есть ли случаи, когда переопределение Equals и GetHashCode и реализация IEquatable<> предпочтительнее использовать StructuralEqualityAttribute. Если да, можно ли это сделать без снижения производительности оператора =?
Для простых структур, содержащих одно целое число, я запустил цикл, который повторяет ту же проверку равенства 1M раз. Я назначил цикл, используя...
-
=с пользовательским (тип и значение) равенство: около 110 мс -
=со структурным равенством: от 20 мс до 25 мс - Пользовательский
==оператор, который перенаправляет на IEquatable: от 1 мс до 3 мс - Пользовательский
==оператор, который сравнивает значения напрямую: 0ms (стирается оптимизатором)
Из того, что я понимаю, интерфейс IEquatable<> может использоваться как оптимизация производительности для предотвращения бокса при проверке равенства. Это похоже на С#, но я вряд ли могу найти упоминания об этом в F #. Кроме того, компилятор F # жалуется при попытке переопределить оператор = для заданного типа.
Атрибут StructuralEquality задокументирован в MSDN для переопределения только Equals и GetHashCode. Тем не менее, это предотвращает явную реализацию IEquatable<>. Однако полученный тип несовместим с IEquatable<MyType>. Мне это не кажется логичным, если структурно приравненный тип не реализует IEquatable<>?
Есть заметка о производительности = в спецификации F # (8.15.6.2 в спецификации 3.0), но я не знаю, что с ней делать:
Примечание. На практике быстрый (но семантически эквивалентный) код испускается для прямых вызовов (=), сравнения, и хэш для всех базовых типов, а более быстрые пути используются для сравнения большинства массивов
Определение "базовых типов", приведенное выше, не представляется полезным читать эту заметку. Это относится к основным типам?
Я в замешательстве. Что происходит? Как выглядит правильная реализация равенства, если тип может использоваться в качестве ключа коллекции или в частых тестах на равенство?