5

入力文字列を解析するマルチスレッドRPCサーバーがあります。Scalaのパーサーコンビネーターライブラリがマルチスレッドセーフではないという問題が発生しました。Parsers.scalaのvarlastNoSuccessがすべての解析で使用されます。この行でNullPointerExceptionが発生します

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

パーサーの1つを拡張するオブジェクトを作成することによってパーサーを実装するデフォルトの方法ですが、それぞれが独自の内部状態を持つようにオンデマンドでパーサーを構築したいので、オブジェクトの代わりにクラスを使用しています。ただし、結果のパターンマッチが必要なため、コンパイルできません。

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オブジェクト(エクストラクタ付き)は、コードが2.7にバックポートされなくなった2009年に追加されました。ただし、実装は非常に単純です。

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(_, _)したがって、一致を1つ1parser.Failure(_, _)つの一致に置き換えることができますparser.Error(_, _)ただし、返される内容に関心がない場合は、次のタイプと照合する方が簡単です。

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

Eugeneによって提案されたように。

于 2011-05-06T12:11:48.597 に答える