我现在正在学习 Scala,我想编写一些愚蠢的小应用程序,比如控制台 Twitter 客户端,或者其他什么。问题是,如何在磁盘上和逻辑上构建应用程序。我知道 python,在那里我会创建一些带有类的文件,然后将它们导入到主模块中,例如 import util.ssh
或 from tweets import Retweet
(强烈希望你不会介意这些名字,它们仅供引用)。但是如何应该我用 Scala 做这些东西?另外,我对 JVM 和 Java 没有太多经验,所以我在这里完全是新手。
最佳答案
我将不同意 Jens ,在这里,虽然不是那么多。
项目布局
我自己的建议是,您可以在 Maven's standard directory layout 上模拟您的努力。 .
以前版本的 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
所以你要把你的源文件放在
myproject/src/main/scala
里面, 对于主程序,或 myproject/src/test/scala
,用于测试。由于这不再起作用,因此有一些替代方法:
giter8 和 sbt.g8
安装 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
np插件
使用软 Prop 的 np plugin对于 sbt。在下面的示例中,插件在
~/.sbt/plugins/build.sbt
上配置,以及它在 ~/.sbt/np.sbt
上的设置, 使用标准的 sbt 脚本。如果您使用 paulp 的 sbt-extras,您需要将这些东西安装在 ~/.sbt
中正确的 Scala 版本子目录下。 ,因为它为每个 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
目录
你可以简单地用
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
源布局
现在,关于源布局。 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 中也足够好,但您必须注意一些异常(exception)情况。
首先,Scala有
object
,这是Java没有的。一个 class
和 object
同名被认为是同伴,这有一些实际意义,但前提是它们在同一个文件中。因此,将伴随类和对象放在同一个文件中。其次,Scala 有一个被称为
sealed class
的概念。 (或 trait
),它将子类(或实现 object
s)限制为在同一文件中声明的那些。这主要是为了创建具有详尽检查的模式匹配的代数数据类型。例如: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
如
Tree
不是 sealed
,那么任何人都可以扩展它,使编译器无法知道匹配是否详尽无遗。不管怎样,sealed
类放在同一个文件中。另一个命名约定是命名包含
package object
的文件。 (对于那个包裹)package.scala
.进口东西
最基本的规则是同一个包中的东西互相看到。所以,把所有的东西都放在同一个包里,你不需要关心什么看到什么。
但是 Scala 也有相对引用和导入。这需要一些解释。假设我的文件顶部有以下声明:
package org.dcsobral.myproject
package model
以下所有内容都将放入包
org.dcsobral.myproject.model
.此外,不仅该包中的所有内容都可见,而且 org.dcsobral.myproject
中的所有内容都可见。也将可见。如果我刚刚声明 package org.dcsobral.myproject.model
相反,然后 org.dcsobral.myproject
将不可见。规则很简单,但一开始可能会让人们有点困惑。这条规则的原因是相对进口。现在考虑该文件中的以下语句:
import view._
这个导入可能是相对的——所有的导入都可以是相对的,除非你用
_root_.
作为前缀。 .可以引用以下包:org.dcsobral.myproject.model.view
, org.dcsobral.myproject.view
, scala.view
和 java.lang.view
.它还可以引用名为 view
的对象。内scala.Predef
.或者它可能是引用名为 view
的包的绝对导入.如果存在多个这样的包,它会根据一些优先规则选择一个。如果您需要导入其他内容,您可以将导入变成绝对导入。
此导入使
view
中的所有内容都在包(无论它在哪里)在其范围内可见。如果它发生在 class
内, 和 object
或 def
,那么可见性将仅限于此。由于 ._
,它导入了所有内容,这是一个通配符。另一种可能如下所示:
package org.dcsobral.myproject.model
import org.dcsobral.myproject.view
import org.dcsobral.myproject.controller
在这种情况下,包
view
和 controller
将是可见的,但您必须在使用它们时明确命名它们:def post(view: view.User): Node =
或者您可以使用进一步的相对导入:
import view.User
import
语句还使您能够重命名内容,或导入除某些内容之外的所有内容。有关更多详细信息,请参阅有关它的相关文档。所以,我希望这能回答你所有的问题。
关于Scala应用程序结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5910791/