这是我在我的小解析器应用程序中使用的基本特征:
trait Token[ValueType] {
def value: ValueType
}
这就是我的要求。我还想结合Java的一个很好的特性和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
子类。
所以,亲爱的Scalists,该怎么办?
答案 0 :(得分:1)
最简单的方法
case Keyword(BEGIN) => ...
只是import
关键字:
import Keywords._
它不会要求对您的代码进行任何其他更改。
答案 1 :(得分:1)
但是,我个人更愿意避免ProperEnumerarion
并且具有简单的特征和案例对象层次结构:
trait Keyword
case object BEGIN extends Keyword
case object CASE extends Keyword
这将自动提供模式匹配:
token match {
case BEGIN => ...
}
如果你需要对象中的某些方法,你可能会在具有一些抽象类(带有构造函数)的特性中声明它们:
abstract class Keyword(val name:String) {
def myMethod = "Keyword."+name
}
case object BEGIN extends Keyword("BEGIN")
case object CASE extends Keyword("CASE")
UPD:您可以使用与枚举实例化“枚举”实例的对象:
object AllMyKeywords {
val BEGIN = Keyword("BEGIN")
val CASE = Keyword("CASE")
// etc.
val values = List(BEGIN, CASE, ...).map(k => (k.name, k)).toMap
}
UPD2:还有一种方法可以与字符串进行模式匹配:
abstract class Keyword(val name:String) {
def unapply(str:String):Option[Keyword] = {
if(AllMyKeywords.values.contains(str))
Some(AllMyKeywords.values(str)
else
None
}
}
在这种情况下,unapply
方法由每个BEGIN
,CASE
关键字实现,因此直接调用(至少我认为是这样)。
"BEGIN" match { case BEGIN => ??? }