Scala:如何在repl中全局安装软件包以进行工作?

18

在Python中,如果我使用 pip install package_name 安装了一个包,无论我当前在文件系统的哪个目录下,只需输入 python,然后按其名称导入该包即可轻松打开Python repl。

就像这样

$ python
Python 2.7.3 (default, Sep 26 2013, 20:03:06) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> 

并且已经导入了requests库,可以在repl中使用它。

在Scala中,我知道如何在使用sbt的项目中完成此操作,但为了学习目的,我想以这种方式安装软件包,以便我可以简单地在命令行中输入scala,然后导入已安装的软件包,而不必绑定到特定的项目。

$ scala
Welcome to Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_40).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scalaz._
<console>:7: error: not found: value scalaz
       import scalaz._

我该怎么做?


1
我认为你指出了Java/Scala相对于Scala的最大弱点之一。 - Daniel
3个回答

16

Scala与Python不同。为Scala 2.9.x编译的代码与2.10.x不兼容。因此,如果您使用不同版本,则全局定义可能会导致许多问题。

您可以使用SBT并添加到$HOME/.sbt/plugins/build.sbt中。

libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.0.4"
或者
libraryDependencies += "org.scalaz" % "scalaz-core_2.10" % "7.0.4"

然后进入 /tmp 目录,并使用 SBT 启动 Scala REPL:

sbt console

但是从长远来看,这不是一个好主意。

最好的方法是安装SBT,创建一个名为build.sbt的文件,并将以下内容放入其中:

libraryDependencies += "org.scalaz" % "scalaz-core_2.10" % "7.0.4"

scalaVersion := "2.10.2" 

initialCommands in console := "import scalaz._, Scalaz._"

现在通过控制台切换到build.sbt所在的文件夹并运行

sbt console

使用SBT,您可以在REPL中进行实验,并已经导入了scalaz并放在类路径中。此外,添加其他依赖项也很容易。 SBT很酷,您无需手动安装新的Scala版本,只需在build.sbt中声明即可。


3
我希望有一个更简单的解决方案。 - Daniel

1
这通常不被推荐,因为大多数 jar 库都是用于与程序员项目一起使用的。此外,与其他生态系统不同,jar 库通常通过某些用户模式库管理工具(如 ivy、maven 或 sbt)进行安装,您可能已经注意到了。
如果您真的想这样做,可以将 jar 安装到 Scala 的 TOOL_CLASSPATH 位置,您可以从随 Scala 发行版捆绑的 scala.bat 或 scala shell 脚本文件中找到它。或者,您可以构建自己的自定义 Scala REPL,它可以从某个配置的位置加载全局可安装的库。无论哪种方式,都需要对 TOOL_CLASSPATH 进行 futzing。

P.S: 我目前无法访问实际的scala.bat文件来帮助您解决此问题,但您可以在这里这里查找以了解我的意思。请注意,这些文件可能不会显示.bat文件的结构,因为它们在分发中(可能相当过时)。请在官方分发中查找信息。

编辑

现在我回来了,看了一下官方分发包含的实际的scala批处理和shell脚本,我可以解释得更详细一些:-)

像我上面说的那样,scala脚本加载其TOOL_CLASSPATH文件夹中存在的所有jar文件,通常为${SCALA_HOME}/lib。 它还提供了使用有前途的-toolcp选项添加到TOOL_CLASSPATH的功能-让我们看看它显示了什么:(批处理脚本类似-我将只展示scala shell脚本中的内容)

while [[ $# -gt 0 ]]; do
  case "$1" in
    -D*)
      # pass to scala as well: otherwise we lose it sometimes when we
      # need it, e.g. communicating with a server compiler.
      java_args=("${java_args[@]}" "$1")
      scala_args=("${scala_args[@]}" "$1")
      shift
      ;;
    -J*)
      # as with -D, pass to scala even though it will almost
      # never be used.
      java_args=("${java_args[@]}" "${1:2}")
      scala_args=("${scala_args[@]}" "$1")
      shift
      ;;
    -toolcp)
      TOOL_CLASSPATH="${TOOL_CLASSPATH}${SEP}${2}"
      shift 2
      ;;
    -nobootcp)
      unset usebootcp
      shift
      ;;
    -usebootcp)
      usebootcp="true"
      shift
      ;;
    -debug)
      SCALA_RUNNER_DEBUG=1
      shift
      ;;
    *)
      scala_args=("${scala_args[@]}" "$1")
      shift
      ;;
  esac
done

如您所见,这样做非常有限 - 您必须指定每个要添加的jar。您可以使用-cp!我们能否使它更好?当然,我们必须在toolcp中进行一些操作。
addtoToolCP() {
    for i in $(find $1 -name "*.jar")
    do
        if [[ -z "$TOOLCP" ]]
        then
            TOOLCP="$i"
        else
            TOOLCP="${TOOLCP}:$i"
        fi
    done
}

因此,您可以检查我们的TOOLCP参数是否为空,并相应地调用scala,如scala -toolcp $TOOLCP如果非空。现在,您可以像这样调用您的shell脚本:myscalascript <list-of-paths-to-be-added-to-toolcp>。或者您可以只保留一个文件夹并继续向其中添加新库。希望这可以帮助 - 正如其他人所说,请注意二进制兼容性问题。二进制不兼容问题只会影响主要的Scala版本,次要版本应该是完全兼容的。最后,为了避免重复自己到死,仅在您确定要使用此选项时使用它。 :-)

1

除了S.R.I之外,我还使用以下解决方案,shell脚本:

/usr/bin/scalaz

    #!/bin/sh
    scala -cp  ~/.ivy2/cache/org.scalaz/scalaz-core_2.10/bundles/scalaz-core_2.10-7.1.0-M3.jar ... other libs

然后在终端中调用它:

$ scalaz
Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_40).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._

scala> Monad[Option].point(1)
res0: Option[Int] = Some(1)

scala>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接