簡體   English   中英

Scala應用程序結構

[英]Scala application structure

我現在正在學習Scala,我想寫一些愚蠢的小應用程序,如控制台Twitter客戶端,或其他什么。 問題是,如何在磁盤上和邏輯上構建應用程序。 我知道python,在那里我只是創建一些帶有類的文件然后在主模塊中導入它們,如import util.ssh或者from tweets import Retweet (強烈希望你不介意這些名字,它們僅供參考)。 但是我應該如何使用Scala來做這些事情呢? 另外,我對JVM和Java沒有多少經驗,所以我在這里是一個完整的新手。

我不同意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

因此,您將源文件放在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插件

使用softprops的sp 插件np插件 在下面的示例中,插件在~/.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創建它:

$ 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.modelorg.dcsobral.myproject.vieworg.dcsobral.myproject.controller ,然后目錄將是myproject/src/main/scala/modelmyproject/src/main/scala/viewmyproject/src/main/scala/controller

  • 將所有東西放在一起。 在這種情況下,所有源文件都在myproject/src/main/scala 這對小型項目來說已經足夠了。 實際上,如果您沒有子項目,則與上述相同。

這涉及目錄布局。

文件名

接下來,我們來談談文件。 在Java中,實踐是將每個類分隔在自己的文件中,該文件的名稱將遵循類的名稱。 這在Scala中也足夠好,但你必須注意一些例外。

首先,Scala具有Java所沒有的object 具有相同名稱的classobject被視為伴隨 ,它具有一些實際含義,但前提是它們位於同一文件中。 因此,將伴侶類和對象放在同一個文件中。

其次,Scala有一個稱為sealed class (或trait )的概念,它將子類(或實現object )限制為在同一文件中聲明的子類。 這主要是為了創建具有模式匹配和窮舉檢查的代數數據類型。 例如:

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內的所有org.dcsobral.myproject也都可見。 如果我只是聲明了package org.dcsobral.myproject.model ,那么org.dcsobral.myproject將不可見。

規則很簡單,但最初可能會讓人感到困惑。 此規則的原因是相對導入。 現在考慮該文件中的以下語句:

import view._

此導入可能是相對的 - 除非您使用_root_.前綴,否則所有導入都可以是相對的_root_. 它可以引用以下包: org.dcsobral.myproject.model.vieworg.dcsobral.myproject.viewscala.viewjava.lang.view 它還可以引用scala.Predef名為view的對象。 或者它可以是一個絕對導入,引用一個名為view的包。

如果存在多個這樣的包,它將根據一些優先規則選擇一個。 如果您需要導入其他內容,可以將導入轉換為絕對導入。

此導入使view包中的所有內容(無論它在何處)在其范圍內可見。 如果它發生在classobjectdef ,則可見性將限制在此范圍內。 它導入所有東西,因為._ ,這是一個通配符。

替代方案可能如下所示:

package org.dcsobral.myproject.model
import org.dcsobral.myproject.view
import org.dcsobral.myproject.controller

在這種情況下, viewcontroller將是可見的,但您在使用它們時必須明確命名它們:

def post(view: view.User): Node =

或者您可以使用進一步的相對導入:

import view.User

import語句還允許您重命名內容,或導入除了某些內容之外的所有內容。 有關詳細信息,請參閱相關文檔。

所以,我希望這能回答你所有的問題。

Scala支持並鼓勵Java / JVM的包結構,幾乎相同的建議適用:

  • 鏡像目錄結構中的包結構。 這在Scala中不是必需的,但它有助於找到自己的方法
  • 使用逆域作為包前綴。 對我而言,這意味着一切都始於de.schauderhaft。 如果您沒有自己的域名,請使用對您有意義的內容
  • 如果頂級類很小並且密切相關,則只將頂級類放在一個文件中。 否則每個文件都有一個類/對象。 例外:伴侶對象與該類位於同一文件中。 密封類的實現進入同一個文件。
  • 如果你的應用程序增長,你可能希望有類似圖層和模塊的東西,並在包結構中鏡像它們,所以你可能有這樣的包結構: <domain>.<module>.<layer>.<optional subpackage>
  • 在包,模塊或層級上沒有循環依賴關系

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM