error: left- and right-associative operators with same precedence may not be mixed

error: left- and right-associative operators with same precedence may not be mixed

我正在尝试在 Scala 中制作 URI DSL,但中缀方法确实给我带来了麻烦。

即使在将冗长且非常不直观的优先级规则记入记忆之后,它们仍然给我带来麻烦。

class Foo {
  def `://`(a: Unit) = this
  def `:`(b: Unit) = this
}

object Foo {
  def main(args: Array[String]): Unit = {
    new Foo `://` {} `:` {}
  }
}

产量

left- and right-associative operators with same precedence may not be mixed
    new Foo `://` {} `:` {}

                ^

这是什么意思?我以为所有运算符都是左关联的。

有什么方法可以让我写出像这样的 DSL 吗?

"https" `://` "example.com" `:` 80

您选择的运营商名称有两个问题:

  • 名称 :// 包含双斜杠,因此如果没有反引号,编译器可能会将其误解为注释
  • Name : 因为所有其他以 : 结尾的运算符创建右关联运算符,这对于像 ::#:: 这样的运算符从头开始构建序列很方便.具有不同关联性的运算符在没有括号的情况下是不允许的,因为不清楚应该从哪里开始构建表达式。

所以我的建议是去掉双斜杠和冒号结尾,这可能会造成一些混乱,但正确的 DSL 语法:

object URILanguage extends App {
  case class URL(protocol: String, hostname: String, port: Option[Int] = None, path: Seq[String] = Nil) {
    def %(port: Int) = copy(port = Some(port))

    def /(component: String) = copy(path = path :+ component)
  }

  implicit class WithHostname(protocol: String) {
    def ~(hostname: String) = URL(protocol, hostname)
  }

  println("http" ~ "example.com" % 8080 / "mysite" / "index.html")
}

来自 The Scala Language Specification,第 6.12.3 节:

The associativity of an operator is determined by the operator’s last character. Operators ending in a colon ‘:’ are right-associative. All other operators are left-associative

编译器不知道是否将您的代码解释为:

80.`:`("https".`://`("example.com"))

或者这个:

"https".`://`(80.`:`("example.com"))

我认为没有办法阻止“:”被视为右结合运算符。您可以通过使用括号来帮助编译器;否则,您必须更改您的运营商名称。