5

我们有一个解析输入字符串的多线程 RPC 服务器。我们遇到了一个问题,Scala 的解析器组合库不是多线程安全的:Parsers.scala 中的 var lastNoSuccess任何解析使用。我们在这一行得到一个 NullPointerException

if (!(lastNoSuccess != null && next.pos < lastNoSuccess.next.pos))

通过创建扩展其中一个解析器的对象来实现解析器的默认方法,但我想按需构造一个解析器,因此每个解析器都有自己的内部状态,所以我使用的是类而不是对象。但是,我无法编译它,因为我需要对结果进行模式匹配:

import scala.util.parsing.combinator.RegexParsers

class SqlParserImpl
  extends RegexParsers
{
  val term: Parser[String] = """(?i)term\b""".r
}

object Test
{
  def main(args: Array[String]): Unit =
  {
    val parser = new SqlParserImpl
    parser.parseAll(parser.term, "term") match {
      // How do I match?
      case SqlParserImpl#Success(result, _) => true
      case SqlParserImpl#NoSuccess => false
    }
  }
}

失败

t.scala:16: error: '=>' expected but '#' found.
          case SqlParserImpl#Success(result, _) => true
                            ^
t.scala:17: error: '=>' expected but '#' found.
          case SqlParserImpl#NoSuccess => false
                            ^
two errors found
4

3 回答 3

11

用这个:

val parser = new SqlParserImpl
parser.parseAll(parser.term, "term") match {
  case parser.Success(result, _) => true
  case parser.NoSuccess(_, _) => false
}

#符号用于指定类型成员。在您的情况下,它使用需要引用对象或看起来像构造函数的东西的构造函数或提取器模式。

唔。我手边没有2.7。尝试这个:

parser.parseAll(parser.term, "term") match {
  case parser.Success(result, _) => true
  case parser.Failure(_, _) => false
  case parser.Error(_, _) => false
}
于 2011-05-06T04:35:31.157 回答
4

我能够编译以下内容:

object Test {  
  def main(args: Array[String]): Unit = {
    val parser = new SqlParserImpl

    println(parser.parseAll(parser.term, "term") match {
      case x: parser.Success[_] => true
      case x: parser.NoSuccess => false
    })
  }
}
于 2011-05-06T03:40:20.600 回答
4

NoSuccess对象(带有提取器)是在 2009 年添加的,当时没有代码被向后移植到 2.7。然而,它的实现非常简单:

object NoSuccess {
  def unapply[T](x: ParseResult[T]) = x match {
    case Failure(msg, next)   => Some(msg, next)
    case Error(msg, next)     => Some(msg, next)
    case _                    => None
  }
}

因此,您可以将parser.NoSuccess(_, _)匹配替换为parser.Failure(_, _)一对一parser.Error(_, _)匹配。但是,如果您对返回的内容不感兴趣,那么匹配类型会更简单:

case _: parser.Success[_] => true
case _: parser.NoSuccess  => false

就像尤金建议的那样。

于 2011-05-06T12:11:48.597 回答