Подтвердить что ты не робот

Как перезагрузить класс или пакет в 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;
4b9b3361

Ответ 1

Перезагрузка классов - непростая задача. Фактически, это то, что JVM делает очень сложно. У вас есть несколько вариантов:

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

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

Ответ 2

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

:replay

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

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

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

Ответ 3

Существует команда, удовлетворяющая вашим требованиям

:load path/to/file.scala

который перезагрузит исходный файл scala и перекомпилируется в классы, тогда вы можете воспроизвести код

Ответ 4

Это работает для меня....

Если ваш новый исходный файл Test.scala выглядит примерно так:

package com.tests

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

Сначала вам нужно загрузить новые изменения в консоль Scala (REPL).

:load src/main/scala/com/tests/examples/Test.scala

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

import com.tests.Test

Теперь наслаждайтесь новым кодом без перезапуска сеанса:)

scala> Test.goodbye
res0: String = Goodbye, Cruel World

Ответ 5

Если файл .scala находится в каталоге, в котором вы запускаете REPL, вы можете опустить полный путь, просто поместите :load myfile.scala, а затем импортируйте.