Java Scala枚举扩展特性

Java Scala枚举扩展特性,java,scala,enums,Java,Scala,Enums,我正在写一个简单的解析器,它是Scala 我有一个基本特征,它表示文件中的一个元素 trait Token[T] { def stringValue: String def value: T } 这就是我所需要的——字符串(文本)值和解析后的值(有时会是相同的字符串)。现在我想要一组子类,用于: 保留符号/关键字,例如类,无效等 特殊符号,如+,/等 整数文本,例如123 真实文字,例如1.23 字符串文字,例如“123” 您将如何实现这样的层次结构?因为这是有限的,所以最

我正在写一个简单的解析器,它是Scala

我有一个基本特征,它表示文件中的一个元素

trait Token[T] {
    def stringValue: String
    def value: T
}
这就是我所需要的——字符串(文本)值和解析后的值(有时会是相同的字符串)。现在我想要一组子类,用于:

  • 保留符号/关键字,例如
    无效
  • 特殊符号,如
    +
    /
  • 整数文本,例如123
  • 真实文字,例如1.23
  • 字符串文字,例如“123”
您将如何实现这样的层次结构?因为这是有限的,所以最好使用case类。。我想。但是列举一下也很好。。如何组合


换句话说,在Scala中以一种更具规模的方式写这篇文章(下面)的最佳方式是什么

public interface Token<T> {
    String stringValue();
    T value();
}

public enum ReservedSymbol implements Token<ReservedSymbol> {
    CLASS('class'), VOID('void');

    private String val;
    private ReservedSymbol(String val) { this.val = val; }

    public String stringValue() { return val; }
    public ReservedSymbol value() { return this; }
}


public class IntegerLiteral implements Token<Integer> {       
    private Integer val;
    public IntegerLiteral(String val) { this.val = Integer.valueOf(val); }

    public String stringValue() { return val.toString(); }
    public Integer value() { return val; }
}
公共接口令牌{
字符串stringValue();
T值();
}
公共枚举ReservedSymbol实现令牌{
类别(“类别”),无效(“无效”);
私有字符串val;
private ReservedSymbol(String val){this.val=val;}
公共字符串stringValue(){return val;}
public ReservedSymbol value(){返回此;}
}
公共类IntegerLiteral实现标记{
私有整数val;
public IntegerLiteral(String val){this.val=Integer.valueOf(val);}
公共字符串stringValue(){return val.toString();}
公共整数值(){return val;}
}
等等。

sealed trait Token[+T]{//sealed意味着它只能在此文件中扩展
def stringValue:String
def值:T
}
//如果您对扩展令牌[ReservedSymbol]感到满意,则可以避免强制转换
//如Java示例所示
//类而不是trait,以便它可以具有构造函数参数

sealed class ReservedSymbol[+T在Scala中构建这样的层次结构时,请尝试应用以下原则:

  • 绘制所需的类层次结构。将其设计为只实例化叶节点,而内部节点是抽象的
  • 将内部节点实现为traits
  • 将叶节点实现为case类
  • 这样做的原因是,case类自动添加了很多有用的魔法(toString、unapply、serialize、equals等),但必要的代码是在away中生成的,与case类之间的继承不兼容(例如)

    通常,不带参数的叶类型通常建模为
    案例对象
    ,而带参数的叶类型建模为
    案例类

    当您需要实例化类型树的内部节点时,只需添加一个人工叶并将其实现为case类/case对象

    您也可以在Scala中使用,但通常情况下,case类更实用。当您需要将给定字符串转换为相应的枚举时,枚举通常是一个很好的选择。您可以使用
    enumeration.withName(string)

    在Alexey Romanov的回答中,您可以看到如何将此原则应用于具有一个根节点和三个叶节点的类型树

  • Token
    (内部节点=>trait)

    1.1.
    ClassSymbol
    (不带参数的叶节点=>case对象)

    1.2.
    VoidSymbol
    (不带参数的叶节点=>案例对象)

    1.3.
    IntegerLiteral
    (带参数的叶节点=>案例类)

  • 使用枚举和案例类的情况示例如下:

    trait Token[T]{
      def stringValue: String 
      def value: T
    }
    
    object ReservedSymbolEnum extends Enumeration {
      type ReservedSymbolEnum = Value
      val `class`, `void` = Value
          val NullValue = Value("null") // Alternative without quoting
    }
    
    case class ReservedSymbol(override val stringValue: String)extends Token[ReservedSymbolEnum.ReservedSymbolEnum] {
      def value = ReservedSymbolEnum.withName(stringValue)
    }
    
    case class StringLiteral(override val stringValue: String) extends Token[String] {
      override def value = stringValue
    }
    
    case class IntegerLitaral(override val stringValue: String) extends Token[Int] {
      override def value = stringValue.toInt
    }
    
    一些用法示例:

    scala> def `void`=ReservedSymbol("void")
    void: ReservedSymbol
    
    scala> `void`.value
    res1: ReservedSymbolEnum.Value = void
    
    scala> def `42`=IntegerLiteral("42")
    42: IntegerLitaral
    
    scala> `42`.value
    res2: Int = 42
    

    你能举一个更长的例子吗?我会有100个关键字(不仅仅是class和void),co为每个符号单独声明一个对象是不好的。这就是为什么我想在JavaEnum中使用Enum谢谢。但是想想我的情况-当尝试为令牌层次结构建模时,你会怎么做?会有大约50个关键字等。我还想创建子层次结构,如Int extends Number、Number extends Token等。请参见上面的编辑。下面的子层次结构是类型树中的内部节点,因此您应该将它们建模为特征。这很好。您对这段代码有何看法:我一直在研究这段代码?看起来不错。您可以将关键字放入枚举中,以使其更安全。您的解决方案与我在链接中的一些想法相结合,看起来非常好。如何d您为运算符定义了枚举/事例类(例如,
    '+='
    )?我不想像对class和void那样对它们进行转义。。
    scala> def `void`=ReservedSymbol("void")
    void: ReservedSymbol
    
    scala> `void`.value
    res1: ReservedSymbolEnum.Value = void
    
    scala> def `42`=IntegerLiteral("42")
    42: IntegerLitaral
    
    scala> `42`.value
    res2: Int = 42