Мне интересно, в каких случаях тесты равенства в 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), но я не знаю, что с ней делать:
Примечание. На практике быстрый (но семантически эквивалентный) код испускается для прямых вызовов (=), сравнения, и хэш для всех базовых типов, а более быстрые пути используются для сравнения большинства массивов
Определение "базовых типов", приведенное выше, не представляется полезным читать эту заметку. Это относится к основным типам?
Я в замешательстве. Что происходит? Как выглядит правильная реализация равенства, если тип может использоваться в качестве ключа коллекции или в частых тестах на равенство?