Enum vs не член дискриминационного союза

Я только что заметил, что существует небольшое различие в объявлении профсоюза, не входящего в дискриминацию:

type Color =
    | Red
    | Green
    | Blue

и объявив перечисление:

type Color =
    | Red = 0 
    | Green = 1
    | Blue = 2

Каковы их основные различия с точки зрения производительности, использования и т. Д.? У вас есть предложения, когда использовать что?

3 ответа

Решение

Enum являются структурами и поэтому размещаются в стеке, тогда как различимые объединения являются ссылочными типами, поэтому они выделяются в куче. Таким образом, вы ожидаете, что DU будет немного менее производительным, чем перечисления, хотя в действительности вы, вероятно, никогда не заметите эту разницу.

Что еще более важно, дискриминируемое объединение может быть только одним из объявленных типов, где перечисления на самом деле являются просто целыми числами, поэтому вы можете привести целое число, которое не является членом перечисления, к типу перечисления. Это означает, что когда сопоставление с образцом компилятор может утверждать, что сопоставление с образцом завершено, когда вы рассмотрели все случаи для DU, но для перечисления вы должны всегда помещать в перехват по умолчанию все остальные случаи, т. Е. Для перечисления всегда будет нужно сопоставление с образцом, как:

match enumColor with
| Red -> 1 
| Green -> 2
| Blue -> 3
| _ -> failwith "not an enum member"

где в последнем случае не будет необходимости с DU.

И последний момент, поскольку перечисления изначально поддерживаются как в C#, так и в VB.NET, а в отличие от DU, перечисления часто являются лучшим выбором при создании общедоступного API для использования другими языками.

В дополнение к тому, что сказал Роберт, сопоставление с образцом в профсоюзах выполняется одним из двух способов. Для объединений только с нулевыми падежами, то есть без связанного значения (это близко соответствует перечислениям), генерируемый компилятором Tag свойство проверено, что является int, В этом случае вы можете ожидать, что производительность будет такой же, как с перечислениями. Для союзов, имеющих ненулевые случаи, используется тест типа, который, я полагаю, также довольно быстрый. Как сказал Роберт, если есть несоответствие производительности, оно незначительно. Но в первом случае все должно быть точно так же.

Что касается присущей "неполноте" перечислений, то, когда сопоставление с образцом не удается, вы действительно хотите знать, является ли допустимое дело совпадением. Как правило, вас не волнует, было ли неверное целочисленное значение приведено к перечислению. В этом случае вы хотите, чтобы матч провалился. Я почти всегда предпочитаю объединения, но когда мне нужно использовать перечисления (обычно для обеспечения взаимодействия), внутри обязательного подстановочного знака я передаю несопоставленное значение функции, которая различает допустимые и недействительные значения и вызывает соответствующую ошибку.

Начиная с F# 4.1 существуют структурно разграниченные объединения.

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

У них превосходное соответствие дискриминационных союзов.

Они специфичны для F#, поэтому, если вам нужно понимать другие языки.Net, вы все равно должны использовать перечисления.

Другие вопросы по тегам