Вопрос по final, field, scala – Почему `val` внутри` object` не является финальным автоматически?

32

В чем причинаvalне является (?) автоматически финальным в одноэлементных объектах? Например.

object NonFinal {
   val a = 0
   val b = 1

   def test(i: Int) = (i: @annotation.switch) match {
      case `a` => true
      case `b` => false
   }
}

результаты в:

:12: error: could not emit switch for @switch annotated match
          def test(i: Int) = (i: @annotation.switch) match {
                                                     ^

В то время как

object Final {
   final val a = 0
   final val b = 1

   def test(i: Int) = (i: @annotation.switch) match {
      case `a` => true
      case `b` => false
   }
}

Компилируется без предупреждений, поэтому, вероятно, генерирует более быструю таблицу сопоставления с образцом.

Нужно добавитьfinal мне кажется чистый раздражающий шум Isn»тobject Само по себе окончательное, а значит и его участники?

Согласовано. Я относительно новичок в Скале ... пытался исследовать возможные пути, о которых вы не думали. Tony K.
@TonyK. - что вы имеете в виду? Даже если бы яtrait T { def a: Int }объект переопределитa в правилах линеаризации. Если бы у меня былоtrait T { def a: Int = 33 }хорошо в этом случаеoverride final val это невозможно. Но я думаю, что это все еще нет дисквалифицировать подход созданиябез наиважнейшая vals final по умолчанию. 0__
Гектометр как насчет черт, которые могут быть использованы? Tony K.
Вы должны изменить принятый ответ на @extempore 'с (Пол Филлипс). В этом случае,final заставляет значение быть встроенным во время компиляции. drstevens

Ваш Ответ

3   ответа
3

я думаю, что этот пункт из спецификации более актуален:

Определение константного значения имеет вид final val x = e, где e - постоянное выражение (§6,24). Окончательный модификатор должен присутствовать, и никакая аннотация типа не может быть дана. Ссылки на постоянное значение x сами по себе рассматриваются как константные выражения; в сгенерированном коде они заменяются определениемс правой стороны е.

По значимости:

Никакая аннотация типа не может быть данаВыражение e используется в сгенерированном коде (по моим прочтениям, в качестве исходного неоцененного константного выражения)

Для меня это звучит так, как будто спецификация требует, чтобы компилятор использовал эти больше как замены макросов, а не значения, которые оцениваются на месте во время компиляции, что может повлиять на работу результирующего кода.

Я думаю, что это особенно интересно, что аннотации типов не могут быть даны.

Это, я думаю, указывает на наш окончательный ответ, хотя я не могу придумать пример, который показывает разницу во времени выполнения для этих требований. На самом деле, в моем переводчике 2.9.2 я недаже получить исполнение первого правила.

21

не спрашиватьпочему нет они финал ", вы'переспрашиваюпочему неТ они встроены. " Просто так получается, что final - это то, как вы указываете компилятору, что вы хотите, чтобы он был встроен.

Причина, по которой они не включаются автоматически, заключается в отдельной компиляции.

object A { final val x = 55 }
object B { def f = A.x }

Когда вы компилируете это, B.f возвращает 55, буквально:

public int f();
  0: bipush        55
  2: ireturn       

Это означает, что если вы перекомпилируете A, B не заметит изменения. Если x не помечен как финальный в A, B.f выглядит следующим образом:

  0: getstatic     #19                 // Field A$.MODULE$:LA$;
  3: invokevirtual #22                 // Method A$.x:()I
  6: ireturn       

Кроме того, чтобы исправить один из других ответов, окончательный не означает неизменяемый в Scala.

финал также не означает константу. Пытаться "окончательный вариант х = 1; х = 2 ". psp
похоже, это должен быть принятый ответ fredoverflow
24

спецификацияи они автоматически становятся окончательными:

Члены конечных классов или объектов неявно также являются окончательными, поэтомуfinal модификатор, как правило, для них тоже избыточен. Обратите внимание, однако, что определения постоянных значений (§4.1) требуют явногоfinal модификатор, даже если они определены в конечном классе или объекте.

ВашfinalПример без компиляции без ошибок (или предупреждений) с 2.10-M7, поэтому яя предполагаю, чтопроблема с@switch проверка в более ранних версиях, и что члены на самом деле являются окончательными.

Обновление: На самом деле это более любопытно, чем я ожидал.если мы скомпилируем следующее с помощью 2.9.2 или 2.10-M7:

object NonFinal {
  val a = 0
}

object Final {
  final val a = 0
}

javap действительно показывает разницу:

public final class NonFinal$ implements scala.ScalaObject {
  public static final NonFinal$ MODULE$;
  public static {};
  public int a();
}

public final class Final$ implements scala.ScalaObject {
  public static final Final$ MODULE$;
  public static {};
  public final int a();
}

Вы видите то же самое, даже если правая часть определений значений не являетсят постоянное выражение.

Так что я'оставлю мой ответ, но этоне окончательно.

Добавьте случай, чтобы увидеть предупреждение в 2.10+. Теперь документ говорит: Примечание: для совпадений с одним или двумя случаями компилятор генерирует инструкции перехода. Аннотирование такого совпадения с помощью @switch не выдает никаких предупреждений. som-snytt
Спасибо, что спецификация довольно ясна, говоряvals нужно явноfinal, Странно, что 2.10.0-M7, возможно, стоит проверить полученный код соответствия шаблона (возможно,@switch молча уронили?) 0__
@ 0__: Вы читаете, что требуется модификатор? Я'Я просто смущен этим сейчас, но интерпретировал бы это как высказывание, по крайней мере, что если бынет никаких шансов на определение постоянного значения (например, мыу нас есть"0".toInt или жеnew A на правой стороне), тоfinal избыточно Travis Brown
Да, я читал это так, хотя яне согласен со спецификацией здесь. Как я уже сказал, я думаю, что этос ненужным шумом. 0__

Похожие вопросы