サーバーサイドSwiftを学ぶ（基礎の基礎の基礎編）


サーバーサイドとかいいつつ、今回はサーバーらしいことは何も書きません。単純にswiftで、SPM(パッケージマネージャ)を使って実行可能バイナリを作って実行してみるところまでです。
ちなみにswiftはXCodeを入れた時に入ったものを使いますが、コーディイングにXCode自体は使いません。私はAtomを使いました。Atomの場合は、 `Preferences` -> `Install` で `swift` で検索して、 `language-swift` と `autocomplete-swift` を入れておくと幸せになれると思います。

## インストール

### Ubuntu

```
$ sudo apt-get install clang
```

### Mac OSX

XCodeを入れて入ればすぐに使えます。

## コマンドラインでSwiftを学ぶ

### こんにちは世界！

とりあえずはお約束のHello World。
こんなソースを書く。

```swift:hello_world.swift
print("Hello World!")
```

実行する。

```
$ swift hello_world.swift

hello world!
```

ふむ。RubyやPythonみたいにインタプリタとして実行できました。

続いてコンパイルしてみます。

```
$ swiftc hello_world.swift

$ ls
hello_world
```

バイナリファイルが生成されました。実行してみます。

```
$ ./hello_world

hello world!
```

あたり前ですがインタプリタもバイナリも実行結果は同じ。


### クラスを書いてみる

続いてクラスを書いて、そのクラスを別ファイルから使ってみます。
まずは、猫の名前を操作するための `Neko` クラスを書きます。ファイル名は `neko.swift` 。

```swift:neko.swift
class Neko {

  // 猫の名前
  var myName = "Goroneko"

  /**
   * 猫の名前を返す.
   */
  public func getName() -> String {
    return myName
  }

  /**
   * 猫の名前を登録する
   */
  public func setName(_ name: String) {
    myName = name
  }
}
```

Swiftの単純なクラスです。 `setName` メソッドで名前を登録し、 `getName` メソッドで名前を取得します。
また、同じディレクトリ内にエントリポイントとなる `main.swift` を書きます。

```swift:main.swift
let neko = Neko()

print(neko.getName())

neko.setName("Tama")
print(neko.getName())
```

`main.swift` 内では、特にimportなどしなくてもいいようです。
コンパイルします。

```
$ swiftc *.swift
```

`main` というファイルができますので、実行します。

```
$ ./main

Goroneko
Tama
```

期待通りの結果ですね。しかし、swiftcコマンドを使ってのビルドでは、なにかと面倒そうなので、パッケージマネージャを使ってみます。

## SPM(Swift Package Manager)によるパッケージ化

`HelloPackage` という名前のパッケージを作ります。

```
$ mkdir HelloPackage
$ cd HelloPackage/
$ swift package init --type executable

Creating executable package: HelloPackage
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/HelloPackage/main.swift
Creating Tests/
```

自動的に色々とファイルができました。 `$ swift package init --type executable` で、 `--type executable` を指定しているのは、こうすると実行可能ファイルを作るプロジェクトになるからです。逆にモジュールなど作る場合は何も指定しません。

まずは、なにも編集せずにこのまま実行します。

```
$ swift run

Compile Swift Module 'HelloPackage' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/HelloPackage

Hello, world!
```

実行できました。
では、ここに新たにDogクラスを追加します。

まずは、プロジェクトのルートディレクトリから見て、 `Sources/HelloPacakge/dog.swift` を作成します。

```swift:Sources/HelloPacakge/dog.swift
class Dog {

  private var name = "Pochi"

  func getName() -> String {
    return name
  }

  func setName(_ newName: String) {
    name = newName
  }
}
```

単純なゲッターとセッターだけのクラスです。

さらに、 `Sources/HelloPackage/main.swift` にもともと書いてあったソースを全て消して、以下のように書き換えます。

```swift:Sources/HelloPackage/main.swift
let dog = Dog()

let name01: String = dog.getName()
print(name01)

dog.setName("Tarou")
let name02: String = dog.getName()
print(name02)
```

では実行してみます。

```
$ swift run

Compile Swift Module 'HelloPackage' (2 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/HelloPackage

Pochi
Tarou
```

やりました。まったく期待通りの動きです。

先ほどはパッケージで直接実行しましたが、今度はビルドして実行可能バイナリを生成してみます。

```
$ swift build

Compile Swift Module 'HelloPackage' (2 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/HelloPackage
```

`swift run` を実行した直後だとこのメッセージは表示されないかもしれません。
では生成されたバイナリを実行してみます。

```
$ ./.build/x86_64-apple-macosx10.10/debug/HelloPackage

Pochi
Tarou
```

## SPMによる外部パッケージの取り込み

どんな言語を使ってもそうですが、全てを自分で実装するのではなく、共通の問題を解決してくれる他のプロジェクトの成果物を使いたくなる時があります。

たとえば、Rubyには `bundler` というツールがあり、 `Gemfile` に依存するライブラリを記述しておけばそれを自動的にダウンロードしてプロジェクトに組み込んでくれます。

同様の仕組みがSwiftにもあり、それが `Swift Package Manager` です（ [ドキュメントはここ](https://swift.org/package-manager/) ）。

では、先ほどの `HelloPackage` に外部ライブラリを組み込んでみましょう。
`HelloPackage` 内にはすでに `Package.swift` というファイルが存在していると思います。この時点での内容はたぶんこんな感じ。

```swift:Package.swift
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "HelloPackage",
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. 
        //  A target can define a module or a test suite.
        // Targets can depend on other targets in this package, 
        //  and on products in packages which this package depends on.
        .target(
          name: "HelloPackage",
          dependencies: []),
    ]
)
```

読みやすさのためにちょっと改行入れましたがこんな感じかと。

ここで、まあなんでも良いんですが、ためしにSwift向けの通信ソケットライブラリ [BlueSocket](https://github.com/IBM-Swift/BlueSocket)を組み込んでみます。
`Package.swift` はこんな感じになります。

```swift:Package.swift
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "HelloPackage",
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(url: "https://github.com/IBM-Swift/BlueSocket.git", from: "1.0.0")
    ],
    targets: [
        // Targets are the basic building blocks of a package. 
        //  A target can define a module or a test suite.
        // Targets can depend on other targets in this package, 
        //  and on products in packages which this package depends on.
        .target(
          name: "HelloPackage",
          dependencies: ["Socket"]),
    ]
)
```

最初のポイントは、 `dependencies: [ ... ]` の中に依存するパッケージを追加で記述しているところです。これ、Webで検索すると結構古い書き方がヒットしますが、ここでは自動生成された `Package.swift` にご丁寧に書き方がコメントで書いてあるのでこれに従います。

```swift:Package.swift
.package(url: "https://github.com/IBM-Swift/BlueSocket.git", from: "1.0.0")
```

それと忘れてはいけないのが、 `targets: [ .target( ... ) ]` のところで、このライブラリを使うターゲットの `dependencies` 内に、今回使用するライブラリの名称を文字列で指定しておくことです。私はこれに気づかなくて小一時間ハマりました...

```swift:Package.swift
    targets: [
        .target(
          name: "HelloPackage",
          dependencies: ["Socket"]),
    ]
```

`BlueSocket`はプロジェクト名で、ライブラリ名としては `Socket` となるようですので、これをdependenciesに追加します。

続いて、このライブラリを使用するソースファイルの先頭にimport文を記述します。今回は `main.swift` にimport文を記述します。

```swift:main.swift
import Socket
```

`main.cf` 全体としてはこんな感じになっていると思います。

```swift:main.swift
import Socket

let dog = Dog()

let name01: String = dog.getName()
print(name01)

dog.setName("Tarou")
let name02: String = dog.getName()
print(name02)
```

折角インポートしたライブラリを全く使っていませんが、試しにこの状態でビルドしてみましょう。

```
$ swift build
```

すると自動的に先ほどの `BlueSocket` がダウンロードされてビルドが実施されます。

では出来上がった実行ファイルを実行してみます。

```
$ ./.build/x86_64-apple-macosx10.10/debug/HelloPackage

Pochi
Tarou
```

ライブラリは使ってませんが、ビルドは成功しました。