我现在正在学习Scala,我想写一些愚蠢的小应用程序,如控制台Twitter客户端,或其他什么.问题是,如何在磁盘上和逻辑上构建应用程序.我知道python,在那里我只是用类创建一些文件然后在主模块中导入它们import util.ssh或者from tweets import Retweet(强烈希望你不介意这些名称,它们仅供参考).但是我应该如何使用Scala来做这些事情呢?另外,我对JVM和Java没有多少经验,所以我在这里是一个完整的新手.
Dan*_*ral 112
我不同意Jens,虽然不是那么多.
我自己的建议是你在Maven的标准目录布局上模拟你的工作.
以前版本的SBT(在SBT 0.9.x之前)会自动为您创建:
dcs@ayanami:~$ mkdir myproject
dcs@ayanami:~$ cd myproject
dcs@ayanami:~/myproject$ sbt
Project does not exist, create new project? (y/N/s) y
Name: myproject
Organization: org.dcsobral
Version [1.0]:
Scala version [2.7.7]: 2.8.1
sbt version [0.7.4]:
Getting Scala 2.7.7 ...
:: retrieving :: org.scala-tools.sbt#boot-scala
confs: [default]
2 artifacts copied, 0 already retrieved (9911kB/134ms)
Getting org.scala-tools.sbt sbt_2.7.7 0.7.4 ...
:: retrieving :: org.scala-tools.sbt#boot-app
confs: [default]
15 artifacts copied, 0 already retrieved (4096kB/91ms)
[success] Successfully initialized directory structure.
Getting Scala 2.8.1 ...
:: retrieving :: org.scala-tools.sbt#boot-scala
confs: [default]
2 artifacts copied, 0 already retrieved (15118kB/160ms)
[info] Building project myproject 1.0 against Scala 2.8.1
[info] using sbt.DefaultProject with sbt 0.7.4 and Scala 2.7.7
> quit
[info]
[info] Total session time: 8 s, completed May 6, 2011 12:31:43 PM
[success] Build completed successfully.
dcs@ayanami:~/myproject$ find . -type d -print
.
./project
./project/boot
./project/boot/scala-2.7.7
./project/boot/scala-2.7.7/lib
./project/boot/scala-2.7.7/org.scala-tools.sbt
./project/boot/scala-2.7.7/org.scala-tools.sbt/sbt
./project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4
./project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-bin_2.7.7.final
./project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-src
./project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/compiler-interface-bin_2.8.0.RC2
./project/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.4/xsbti
./project/boot/scala-2.8.1
./project/boot/scala-2.8.1/lib
./target
./lib
./src
./src/main
./src/main/resources
./src/main/scala
./src/test
./src/test/resources
./src/test/scala
Run Code Online (Sandbox Code Playgroud)
因此,您将把源文件放在myproject/src/main/scala主程序中,或者myproject/src/test/scala放在测试中.
由于这不再起作用,有一些替代方案:
安装giter8,克隆ymasory的sbt.g8模板并根据您的需要进行调整,并使用它.例如,参见下面未修改的ymasory的sbt.g8模板的使用.我认为这是开始新项目的最佳选择之一,因为你对所有项目都有一个很好的概念.
$ g8 ymasory/sbt
project_license_url [http://www.gnu.org/licenses/gpl-3.0.txt]:
name [myproj]:
project_group_id [com.example]:
developer_email [john.doe@example.com]:
developer_full_name [John Doe]:
project_license_name [GPLv3]:
github_username [johndoe]:
Template applied in ./myproj
$ tree myproj
myproj
??? build.sbt
??? LICENSE
??? project
? ??? build.properties
? ??? build.scala
? ??? plugins.sbt
??? README.md
??? sbt
??? src
??? main
??? scala
??? Main.scala
4 directories, 8 files
Run Code Online (Sandbox Code Playgroud)
使用softprops的sp 插件的np插件.在下面的示例中,使用标准sbt脚本配置插件~/.sbt/plugins/build.sbt及其设置~/.sbt/np.sbt.如果你使用paulp的sbt-extras,你需要在正确的Scala版本子目录下安装这些东西~/.sbt,因为它为每个Scala版本使用单独的配置.在实践中,这是我经常使用的那个.
$ mkdir myproj; cd myproj
$ sbt 'np name:myproj org:com.example'
[info] Loading global plugins from /home/dcsobral/.sbt/plugins
[warn] Multiple resolvers having different access mechanism configured with same name 'sbt-plugin-releases'. To avoid conflict, Remove duplicate project resolvers (`resolvers`) or rename publishing resolver (`publishTo`).
[info] Set current project to default-c642a2 (in build file:/home/dcsobral/myproj/)
[info] Generated build file
[info] Generated source directories
[success] Total time: 0 s, completed Apr 12, 2013 12:08:31 PM
$ tree
.
??? build.sbt
??? src
? ??? main
? ? ??? resources
? ? ??? scala
? ??? test
? ??? resources
? ??? scala
??? target
??? streams
??? compile
??? np
??? $global
??? out
12 directories, 2 files
Run Code Online (Sandbox Code Playgroud)
您可以使用mkdir以下命令创建它:
$ mkdir -p myproj/src/{main,test}/{resource,scala,java}
$ tree myproj
myproj
??? src
??? main
? ??? java
? ??? resource
? ??? scala
??? test
??? java
??? resource
??? scala
9 directories, 0 files
Run Code Online (Sandbox Code Playgroud)
现在,关于源布局.Jens建议遵循Java风格.嗯,Java目录布局是一项要求 - 在Java中.Scala没有相同的要求,因此您可以选择是否遵循它.
如果你遵循它,假设基础包是org.dcsobral.myproject,那么该包的源代码将被放入内部myproject/src/main/scala/org/dcsobral/myproject/,以此类推子包.
偏离该标准的两种常见方式是:
省略基本包目录,仅创建子包的子目录.
举例来说,假设我有包org.dcsobral.myproject.model,org.dcsobral.myproject.view和org.dcsobral.myproject.controller,那么目录将是myproject/src/main/scala/model,myproject/src/main/scala/view和myproject/src/main/scala/controller.
将所有东西放在一起.在这种情况下,所有源文件都在里面myproject/src/main/scala.这对小型项目来说已经足够了.实际上,如果您没有子项目,则与上述相同.
这涉及目录布局.
接下来,我们来谈谈文件.在Java中,实践是将每个类分隔在自己的文件中,该文件的名称将遵循类的名称.这在Scala中也足够好,但你必须注意一些例外.
首先,Scala有object,Java没有.A class和object同名被认为是伴侣,它具有一些实际意义,但前提是它们在同一个文件中.因此,将伴侣类和对象放在同一个文件中.
其次,Scala有一个称为sealed class(或trait)的概念,它将子类(或实现objects)限制为在同一文件中声明的子类.这主要是为了创建具有模式匹配和穷举检查的代数数据类型.例如:
sealed abstract class Tree
case class Node(left: Tree, right: Tree) extends Tree
case class Leaf(n: Int) extends Tree
scala> def isLeaf(t: Tree) = t match {
| case Leaf(n: Int) => println("Leaf "+n)
| }
<console>:11: warning: match is not exhaustive!
missing combination Node
def isLeaf(t: Tree) = t match {
^
isLeaf: (t: Tree)Unit
Run Code Online (Sandbox Code Playgroud)
如果Tree不是sealed,那么任何人都可以扩展它,使编译器无法知道匹配是否是详尽的.无论如何,sealed类在同一个文件中一起出现.
另一个命名约定是命名包含package object(对于该包)的文件package.scala.
最基本的规则是同一个包中的东西互相看见.所以,把所有东西都放在同一个包里,你不需要关心自己看到了什么.
但Scala也有相对引用和导入.这需要一些解释.假设我的文件顶部有以下声明:
package org.dcsobral.myproject
package model
Run Code Online (Sandbox Code Playgroud)
以下所有内容都将放入包装中org.dcsobral.myproject.model.此外,不仅包装内的所有内容都可见,而且内部的所有内容org.dcsobral.myproject也都可见.如果我只是声明package org.dcsobral.myproject.model,那么org.dcsobral.myproject就不可见了.
规则很简单,但最初可能会让人感到困惑.此规则的原因是相对导入.现在考虑该文件中的以下语句:
import view._
Run Code Online (Sandbox Code Playgroud)
此导入可能是相对的 - 除非您使用前导,否则所有导入都可以是相对的_root_..它可以指以下软件包:org.dcsobral.myproject.model.view,org.dcsobral.myproject.view,scala.view和java.lang.view.它也可以引用一个名为viewinside 的对象scala.Predef.或者它可以是一个绝对导入,引用一个名为的包view.
如果存在多个这样的包,它将根据一些优先规则选择一个.如果您需要导入其他内容,可以将导入转换为绝对导入.
此导入使view包中的所有内容(无论它在何处)在其范围内可见.如果它发生在a class和/ object或a中def,则可见性将限制在此范围内.它导入所有东西,因为._它是一个通配符.
替代方案可能如下所示:
package org.dcsobral.myproject.model
import org.dcsobral.myproject.view
import org.dcsobral.myproject.controller
Run Code Online (Sandbox Code Playgroud)
在这种情况下,包 view和controller将是可见的,但你必须在使用它们时明确他们的名字:
def post(view: view.User): Node =
Run Code Online (Sandbox Code Playgroud)
或者你可以使用进一步的相对导入:
import view.User
Run Code Online (Sandbox Code Playgroud)
该import语句还允许您重命名内容,或导入除了某些内容之外的所有内容.有关详细信息,请参阅相关文档.
所以,我希望这能回答你所有的问题.
Jen*_*der 13
Scala支持并鼓励Java/JVM的包结构,几乎相同的建议适用:
<domain>.<module>.<layer>.<optional subpackage>.