我刚刚注意到声明非成员歧视工会只有一点点区别:
type Color =
| Red
| Green
| Blue
并声明一个枚举:
type Color =
| Red = 0
| Green = 1
| Blue = 2
它们在性能、使用等方面的主要区别是什么?你有什么建议什么时候用什么?
我刚刚注意到声明非成员歧视工会只有一点点区别:
type Color =
| Red
| Green
| Blue
并声明一个枚举:
type Color =
| Red = 0
| Green = 1
| Blue = 2
它们在性能、使用等方面的主要区别是什么?你有什么建议什么时候用什么?
枚举是结构,因此分配在堆栈上,而区分联合是引用类型,因此是堆分配的。因此,您会期望 DU 的性能略低于枚举,但实际上您可能永远不会注意到这种差异。
更重要的是,可区分联合只能是声明的类型之一,因为枚举实际上只是一个整数,因此您可以将一个不是枚举成员的整数强制转换为枚举类型。这意味着当模式匹配时,编译器可以断言模式匹配已完成,当您涵盖了 DU 的所有情况时,但是对于枚举,您必须始终放入默认捕获所有其余情况,即对于您的枚举'总是需要模式匹配,如:
match enumColor with
| Red -> 1
| Green -> 2
| Blue -> 3
| _ -> failwith "not an enum member"
最后一种情况对于 DU 是不必要的。
最后一点,由于 C# 和 VB.NET 都原生支持枚举,而 DU 不支持枚举,因此在创建公共 API 以供其他语言使用时,枚举通常是更好的选择。
In addition to what Robert has said, pattern matching on unions is done in one of two ways. For unions with only nullary cases, i.e., cases without an associated value (this corresponds closely to enums), the compiler-generated Tag
property is checked, which is an int
. In this case you can expect performance to be the same as with enums. For unions having non-nullary cases, a type test is used, which I assume is also pretty fast. As Robert said, if there is a performance discrepancy it's negligible. But in the former case it should be exactly the same.
Regarding the inherent "incompleteness" of enums, when a pattern match fails what you really want to know is if a valid case wasn't covered by the match. You don't generally care if an invalid integer value was casted to the enum. In that case you want the match to fail. I almost always prefer unions, but when I have to use enums (usually for interoperability), inside the obligatory wildcard case I pass the unmatched value to a function that distinguishes between valid and invalid values and raises the appropriate error.
As of F# 4.1 there are struct discriminated unions.
These have the performance benefits of stack allocation, like enums.
They have the superior matching of discriminated unions.
They are F# specific so if you need to be understood by other .Net languages you should still use enums.