Структура приложения скала



Я изучаю Scala сейчас, и я хочу написать какое-то глупое маленькое приложение, такое как консольный клиент Twitter, или что-то еще. Вопрос в том, как структурировать приложение на диске и логически. Я знаю python, и там я бы просто создал некоторые файлы с классами, а затем импортировал их в основной модуль, например import util.ssh или from tweets import Retweet (сильно надеясь, что вы не возражаете, что имена, они просто для справки). Но как должны Я делаю это с помощью Scala? Кроме того, у меня не так много опыта с JVM и Java, так что я полный новичок здесь.

592   2  

2 ответов:

я не соглашусь с Йенс, здесь, хотя и не все так много.

Макет Проекта

мое собственное предложение заключается в том, что вы моделируете свои усилия на стандартный макет каталога Maven.

предыдущие версии SBT (до SBT 0.9.х) создаст его автоматически для вас:

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, sbt.g8 шаблон и адаптировать его к вашим потребностям, и использовать это. См. ниже, например, это использование немодифицированного sbt ymasory.шаблон Г8. Я думаю, что это одна из лучших альтернатив для запуска новых проектов, когда у вас есть хорошее представление о том, что вы хотите во всех ваших проекты.

$ g8 ymasory/sbt
project_license_url [http://www.gnu.org/licenses/gpl-3.0.txt]:
name [myproj]:
project_group_id [com.example]:
developer_email [[email protected]]:
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 плагин np для sbt. В приведенном ниже примере плагин настроен на ~/.sbt/plugins/build.sbt, и его параметры ~/.sbt/np.sbt, со стандартным сценарием sbt. Если вы используете sbt-extras paulp, вам нужно будет установить эти вещи в правильном подкаталоге Scala version в ~/.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

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

Макет Источник

теперь об исходном макете. Йенс рекомендует следовать стилю 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 тоже, но вы должны обратите внимание на некоторые исключения.

во-первых, у Скалы есть 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

The import заявление также позволяет переименовывать вещи или импортировать все, кроме чего-то. См. соответствующую документацию об этом для получения более подробной информации.

Итак, я надеюсь, что это ответит на все ваши вопросы.

Scala поддерживает и поощряет структуру пакетов Java /JVM и в значительной степени те же рекомендации применяются:

  • зеркальное отображение структуры пакета в структуре каталогов. Это не обязательно в Scala, но это помогает найти свой путь вокруг
  • используйте свой обратный домен в качестве префикса пакета. Для меня это означает, что все начинается с де.шаудерхафт. Используйте то, что имеет смысл для вас, если у вас нет собственного домена
  • только положить сверху классы уровня в одном файле, если они малы и тесно связаны. В противном случае придерживайтесь одного класса/объекта на файл. Исключения: сопутствующие объекты попадают в тот же файл, что и класс. Реализации запечатанного класса идут в тот же файл.
  • если ваше приложение растет, вы можете иметь что-то вроде слоев и модулей и отражать их в структуре пакета, поэтому у вас может быть такая структура пакета: <domain>.<module>.<layer>.<optional subpackage>.
  • не имеют циклических зависимостей от пакета, модуля или уровень слоя

Comments

    Ничего не найдено.