You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在独立测试类中测试fastparse解析器并匹配完整字符串?

FastParse解析器测试中隐式参数缺失问题解决

问题场景

编写了FastParse解析器:

object MyParser:
  def int[$: P]: P[Int] = digit.rep(1).!.map(s => s.toInt)
  def digit[$: P]: P[Unit] = CharIn("0-9")

需要在独立测试类中单独测试每个解析器,且要求测试时必须匹配完整字符串(部分匹配视为失败),因此编写测试类:

class MyParserTest extends AnyFunSuite with Matchers:
  def parseAll[$: P, T](p: => P[T]): P[T] = Start ~ p ~ End

  test("int parses correctly") {
    fastparse.parse("1234", parseAll(MyParser.int)) shouldBe Success(1234, 4)
  }

运行时触发错误:

No given instance of type fastparse.ParsingRun[$] was found for an implicit parameter 
of method int in object MyParser

where:    $ is a type variable

直接调用fastparse.parse("1234", MyParser.int)无问题,尝试过导入MyParser.given、将parseAll移入MyParser均无效。

问题原因

错误根源在于parseAll的参数p: => P[T]是按名称调用的,Scala不会自动将parseAll上下文里的隐式P[$]传递给MyParser.int的调用。MyParser.int需要隐式的ParsingRun[$]实例,但在按名称参数的求值过程中,这个隐式无法被正确捕获。

解决方案

方案一:显式传递隐式参数

修改parseAll,让它接收一个依赖隐式P[$]的函数,内部显式传递隐式参数:

class MyParserTest extends AnyFunSuite with Matchers:
  def parseAll[$: P, T](p: Given[P[$]] => P[T]): P[T] = 
    Start ~ p(given) ~ End

  test("int parses correctly") {
    fastparse.parse("1234", parseAll(MyParser.int)) shouldBe Success(1234, 4)
  }

方案二:调整参数类型

直接将parseAll的参数改为非按名称类型,确保隐式参数能正确传递:

class MyParserTest extends AnyFunSuite with Matchers:
  def parseAll[$: P, T](p: P[T]): P[T] = Start ~ p ~ End

  test("int parses correctly") {
    fastparse.parse("1234", parseAll(MyParser.int)) shouldBe Success(1234, 4)
  }

验证效果

修改后,测试会强制匹配完整字符串:

  • 输入"1234"会返回Success(1234, 4)
  • 输入"123abc"会解析失败,因为无法匹配End,符合测试要求。

内容的提问来源于stack exchange,提问作者Todd O'Bryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 10:22:35