C#如何实现带标记的枚举?Scala如何解决同样的问题?[副本]

acruukt9  于 2023-05-17  发布在  Scala
关注(0)|答案(1)|浏览(122)

此问题已在此处有答案

Scala bitwise-like method argument(1个答案)
7天前关闭
我正在尝试理解Flagged Enums在C#中是如何工作的,以及我如何在Scala中实现类似的功能。
我很惊讶Enum,这是一种特殊的数据类型,使变量成为一组预定义的常量,实际上可以是枚举的组合,并在C#中编译如下:

[Flags]
enum Permissions
{
  None = 0,
  Read = 1,
  Write = 2,
  Execute = 4
}
// ...

Permissions x = Permissions.Read | Permissions.Write;  # How | Is Implemented???

然而,当我试图在Scala中创建一个枚举或ADT时,我无法实现|操作符,因为我无法从this和other构造新的Permissions:权限。
目前,我知道Enumeration和Enumeratum等库,以及ADT和Scala 3,但我还没有找到使用这些方法创建Flagged Enum的方法。
具体来说,我想知道|运算符在C#中如何与Enums一起工作,以及如何在Scala中实现。
有没有人能解释一下在C#中如何实现Flagged Enums,并提供一些关于如何在Scala中实现类似功能的指导?

dwbf0jvd

dwbf0jvd1#

不像Scala枚举,据我所知它只能有固定数量的示例。C#枚举只是整数类型的简单 Package 。没有任何东西可以阻止任何人创建一个Permissions来 Package 值12334567(并不是说这有意义):

var p = (Permissions)1234567;

|只是 Package 整数值的按位OR。本规范在此处指定:
每个枚举类型E隐式地提供以下预定义的逻辑运算符:

E operator &(E x, E y);
E operator |(E x, E y);
E operator ^(E x, E y);

计算x «op» y的结果,其中x和y是具有底层类型U的枚举类型E的表达式,并且«op»是逻辑运算符之一,与计算(E)((U)x «op»(U)y)完全相同。换句话说,枚举类型逻辑运算符只是对两个操作数的基础类型执行逻辑运算。
这里的“底层类型”是整数类型。默认情况下为int
您可以在Scala中轻松实现类似的东西,只需编写一个围绕Int的 Package 器。为|添加一个运算符重载,并在伴随对象中添加一些命名常量。

// this is just the general idea - excuse me if this is not idiomatic
// I'm not very familiar with Scala
final class Permissions private(private val value: Int) {
  def |(other: Permissions) = new Permissions(value | other.value)
  def hasFlag(flag: Permissions) = (value & flag.value) > 0
}
object Permissions {
  val None = new Permissions(0)
  val Read = new Permissions(1)
  val Write = new Permissions(2)
  val Execute = new Permissions(4)
}

// this works!
val permission = Permissions.Read | Permissions.Write
println(permission.hasFlag(Permissions.Read)) // true
println(permission.hasFlag(Permissions.Write)) // true
println(permission.hasFlag(Permissions.Execute)) // false

带有[Flags]的C#枚举也有一个ToString的自定义实现,它输出值具有的所有标志。您可以在Scala中编写类似的toString实现。

相关问题