Является ли Scala `match` конструкцией синтаксического сахара? Если да, то как это работает?

В

trait Expr
case class Number(n: Int) extends Expr
case class Sum(e1: Expr, e2: Expr) extends Expr

object CaseExample {
  def eval(e: Expr): Int = e match {
    case Number(n) => n
    case Sum(e1, e2) => eval(e1) + eval(e2)
  }
  def main(args: Array[String]) {
    println(eval(Sum(Number(1), Number(2))))       //> 3
  }
}

там происходит довольно много синтаксического сахара. я понимаю case неявно создает два объекта

object Number extends Expr {
  def apply(n: Int) = new Number(n)
}
object Sum extends Expr {
  def apply(e1: Expr, e2: Expr) = new Sum(e1, e2)
}

и именно поэтому мы можем написать, например, Sum(...) и до сих пор создавать экземпляр объекта через класс, так как Sum(...) также синтаксический сахар для Sum.apply(...),

Я прав, что match построить также синтаксический сахар? Если да, то как, например case Number(n) переписан компилятором?

Я спрашиваю, потому что я не вижу этого n в case Number(n) где угодно определено и / или связано со значением. Как ни странно, в match Конструкция регистра первой буквы имеет значение (если она в верхнем регистре будет константой). Это странно, потому что, насколько я знаю, это только в match построить релевантность, поэтому я понятия не имею, как это будет обезвожено.

1 ответ

Да, match является синтаксическим сахаром. Это вызывает unapply метод на вашем объекте. Даниэль Вестхайде имеет хороший пост в блоге об этом.

В частности, когда вы определяете case class за Numberвот что на самом деле генерирует компилятор:

case class Number(n: scala.Int) extends scala.AnyRef with Expr with scala.Product with scala.Serializable {
  val n: scala.Int = { /* compiled code */ }
  /* omitted for brevity */
}
object Number extends scala.runtime.AbstractFunction1[scala.Int, Number] with scala.Serializable {
  def this() = { /* compiled code */ }
  final override def toString(): java.lang.String = { /* compiled code */ }
  def apply(n: scala.Int): Number = { /* compiled code */ }
  def unapply(x$0: Number): scala.Option[scala.Int] = { /* compiled code */ }
}

Как видите, Number сопутствующий объект поставляется с компилятором unapply метод.

Вы можете найти подробное описание дизайна механизма сопоставления с образцами Scala здесь.

-- РЕДАКТИРОВАТЬ --

Если вы хотите увидеть фактический код, сгенерированный компилятором, запустите scalac -print Number.scala, Вот соответствующие биты:

<synthetic> object Number extends scala.runtime.AbstractFunction1 with Serializable {
  /* ... */
  case <synthetic> def unapply(x$0: Number): Option = if (x$0.==(null))
    scala.this.None
  else
    new Some(scala.Int.box(x$0.n()));
  /* ... */
}

Если вы напишите match выражение, вы можете так же запустить scalac -print чтобы увидеть, как match сам обескуражен (в основном: if а также else выражения).

Другие вопросы по тегам