Как перезагрузить класс или пакет в Scala REPL?

У меня почти всегда есть сессия Scala REPL или два открытых, который делает очень легким дать Java или классам Scala быстрый тест. Но если я изменяю класс и перекомпилировал его, REPL продолжает старый загруженный. Существует ли способ заставить это перезагружать класс, вместо того, чтобы иметь необходимость перезапустить REPL?

Только для предоставления конкретного примера предположите, что у нас есть файл Test.scala:

object Test { def hello = "Hello World" }

Мы компилируем его и запускаем REPL:

~/pkg/scala-2.8.0.Beta1-prerelease$ bin/scala
Welcome to Scala version 2.8.0.Beta1-prerelease
(Java HotSpot(TM) Server VM, Java 1.6.0_16).
Type in expressions to have them evaluated.
Type :help for more information.

scala> Test.hello
res0: java.lang.String = Hello World

Затем мы изменяем исходный файл на

object Test {
  def hello = "Hello World"
  def goodbye = "Goodbye, Cruel World"
}

но мы не можем использовать его:

scala> Test.goodbye
<console>:5: error: value goodbye is not a member of object Test
       Test.goodbye
            ^

scala> import Test;
<console>:1: error: '.' expected but ';' found.
       import Test;
44
задан Jacek Laskowski 14 October 2015 в 09:22
поделиться

2 ответа

Перезагрузка классов - непростая проблема. На самом деле, это то, что JVM делает очень сложным. Однако у вас есть несколько вариантов:

  • Запустите Scala REPL в режиме отладки. Отладчик JVM имеет встроенную перезагрузку, которая работает на уровне метода. Это не поможет вам в случае, который вы привели, но это поможет справиться с чем-то простым, например, с изменением реализации метода.
  • Используйте JRebel (http://www.zeroturnaround.com/jrebel). JRebel - это, по сути, суперзаряженное решение по перезагрузке классов для JVM. Он может обрабатывать добавление/удаление членов, новые/удаленные классы, изменения определений и т.д. Практически единственное, что он не может обработать, это изменения в иерархии классов (добавление супер-интерфейса, например. например). Это не бесплатный инструмент, но они предлагают дополнительную лицензию, которая ограничена компиляционными единицами Scala.

К сожалению, оба этих инструмента ограничены деталями реализации Scala REPL. Я использую JRebel, и обычно это помогает, но все равно бывают случаи, когда REPL не отражает перезагруженный класс(ы). Тем не менее, это лучше, чем ничего.

28
ответ дан 26 November 2019 в 22:04
поделиться

Существует альтернатива перезагрузке класса, если цель состоит в том, чтобы не повторять предыдущие команды. REPL имеет команду

:replay

, которая перезапускает среду REPL и воспроизводит все предыдущие допустимые команды. (Недействительные пропускаются, поэтому, если раньше это было неправильно, это не сработает внезапно.) Когда REPL сбрасывается, он перезагружает классы, поэтому новые команды могут использовать содержимое перекомпилированных классов (фактически, старые команды также будут использовать эти перекомпилированные классы).

Это не общее решение, но полезный ярлык для расширения отдельного сеанса с помощью повторно вычисляемого состояния.

Примечание: это относится к голому Scala REPL. Если вы запустите его из SBT или какой-либо другой среды, он может работать или не работать в зависимости от того, как SBT или другая среда упаковывает классы - если вы не обновите то, что находится на фактическом используемом пути к классам, конечно, он выиграет ' т работать!

40
ответ дан 26 November 2019 в 22:04
поделиться
Другие вопросы по тегам:

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