2

这是我在我的小型解析器应用程序中使用的基本特征:

trait Token[ValueType] {
    def value: ValueType
}

这就是我的要求。我还想将 Java 的一个很好的特性与 Scala 的一个很好的特性结合起来,即:

  • 枚举的 Java 方法(它们是带有方法的普通对象,可以 ihnerit 等)
  • Scala 支持匹配(可读代码)

所以类扩展的一个例子Token是:

// this to emulate Java enums; ProperEnumeration just adds some simple methods like fromChars etc.
object Keywords extends ProperEnumeration {
    val AND, ARRAY, BEGIN, CASE, CONST, ... = Value
}

// this to enable matching
final case class Keyword(keyword: Keywords.Value) extends Token[Keywords.Value] {
    def this(string: String) = this(Keywords.fromString(string))   
    def value = keyword
}

object SpecialSymbols extends ProperEnumeration {
    val LEFT_BRACE = Value("{")
    val RIGHT_BRACE = Value("}")
    ...
}

final case class SpecialSymbol(symbol: SpecialSymbols.Value) extends Token[SpecialSymbols.Value]     {
    def this(symbol: String) = this(SpecialSymbols.fromString(symbol))
    def value = symbol
}

// there are also non-enum subclasses of Token
case class Identifier(identifier: String) extends Token[String] {
    override def value: String = identifier
}

这是我想出的最好的。我可以这样使用它:

token match {
    case Keyword(Keywords.BEGIN) => ...
    case SpecialSymbol(SpecialSymbols.LEFT_BRACE) => ...
    case Identifier(name) => ...
}

我想修改它以使我更简洁,我想要这样的东西:

token match {
        case Keyword.BEGIN => ... // or Keyword(BEGIN)
        case SpecialSymbol.LEFT_BRACE => ...
        case Identifier(name) => ...
    }

还支持一个consume可以与任何类型的Token子类一起使用的方法(consume如果来自源的下一个标记不是提供的参数,则应该抛出异常)。

consume(Keyword.BEGIN);
consume(SpecialSymbol.LEFT_BRACE);
consume(Identifier(name));

我希望代码干净,这就是我首先使用 Scala 的原因。所以我希望没有函数重载可以轻松添加Trait子类。

那么,亲爱的 Scalaists,该怎么办?

4

2 回答 2

1

However, I personally would prefer to avoid ProperEnumerarion and have a simple hierarchy of traits and case objects:

trait Keyword
case object BEGIN extends Keyword
case object CASE extends Keyword

This will automatically give pattern matching:

token match {
  case BEGIN => ...
}

If you need some methods in objects you may have them declared in the trait of have some abstract class (with a constructor):

abstract class Keyword(val name:String) {
  def myMethod = "Keyword."+name
}
case object BEGIN extends Keyword("BEGIN")
case object CASE extends Keyword("CASE")

UPD: You may use an object that instantiates "enum" instances the same way as Enumeration:

object AllMyKeywords {
  val BEGIN = Keyword("BEGIN")
  val CASE = Keyword("CASE")
  // etc.
  val values = List(BEGIN, CASE, ...).map(k => (k.name, k)).toMap
}

UPD2: There is also a way to make pattern matching with strings:

abstract class Keyword(val name:String) {
  def unapply(str:String):Option[Keyword] = {
    if(AllMyKeywords.values.contains(str))
      Some(AllMyKeywords.values(str)
    else
      None
  }
}

In this case the unapply method is implemented by every BEGIN, CASE keywords and thus it is directly called (at least I think so).

"BEGIN" match { case BEGIN => ??? }
于 2013-11-11T18:56:58.477 回答
1

最简单的拥有方式

case Keyword(BEGIN) => ...

是简单import的关键字:

import Keywords._

它不需要对您的代码进行任何其他更改。

于 2013-11-11T18:52:15.247 回答