Scala enum扩展特性

Sir*_*mil 2 java enums scala

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

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

trait Token[T] {
    def stringValue: String
    def value: T
}
Run Code Online (Sandbox Code Playgroud)

这就是我需要的 - 字符串(文本)值和解析的值(有时会是相同的字符串).现在我想要一组子类:

  • 保留符号/关键字例如class,void
  • 特殊符号例如+,/等等.
  • 整数文字,例如123
  • 真正的文字,例如1.23
  • 字符串文字,例如'123'

你会如何实现这样的层次结构?由于这是有限的,所以使用案例类很好..我想.但是枚举也会很棒..如何结合?


换句话说,在Scala中以更加Scal-ish的方式编写这个(下面)的最佳方法是什么?

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; }
}
Run Code Online (Sandbox Code Playgroud)

等等

ste*_*hke 5

在Scala中构建此类层次结构时,请尝试应用以下原则:

  1. 绘制所需的类层次结构.设计它的方式是只实例化叶子节点,内部节点是抽象的.
  2. 将内部节点实现为特征
  3. 将叶节点实现为案例类

原因是,case类自动添加了很多有用的魔法(toString,unapply,serialize,equals等).但是必要的代码是在远程生成的,与case类之间的继承不兼容(例如equals不能正常工作).

通常,没有参数的叶子类型通常被建模为case object具有参数的叶子类型被建模为case class.

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

您也可以在Scala中使用Enumerations,但通常情况下的类更实用.当您需要将给定字符串转换为相应的枚举时,枚举通常是一个不错的选择.你可以这样做Enumeration.withName(String).

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

  1. Token (内部节点=>特征)

    1.1.ClassSymbol(没有参数的叶子节点=> case对象)

    1.2. VoidSymbol(没有参数的叶子节点=> case对象)

    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
}
Run Code Online (Sandbox Code Playgroud)

一些用法示例:

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
Run Code Online (Sandbox Code Playgroud)