White Box技術部

WEB開発のあれこれ(と何か)

Swift学習の話 〜WEB+DB PRESSを片手に〜

相変わらず統一性がないですが、今回はSwiftに関してです。

WEB+DB PRESSでのSwift特集

年末のドタバタで読んでいなかった、vol.84のWEB+DB PRESSSwift特集が載っていたので、一通りやってみました。

WEB+DB PRESS Vol.84|技術評論社

Swiftは、公式ドキュメントを読んだり、ネットのサンプルコードを読んだりして、ちまちまコードは書いていましたが、あまり理解できている実感がなかったので、基本部分がまとまっている本特集は助かりました。

実際片手は辛い

いきなり話が逸れますが、こういう手を動かす系の本を読むとき、どうするのが学習しやすいのでしょうか?

私は別の用途で買った、本を開いて立てかけるスタンドを使ったり、先にコード打って、後から本を読んだりしていますが、ディスプレイと本とを視線が行き来する回数が多くなるほど、集中力が減ってしまい、あまり効率良く学習できていない気がしています。

色々試してみて、今はコードを書いて補足的に本を読むスタイルに落ち着きつつありますが、皆さんどうしているのでしょうか?
私、気になります!

コンパイラのある喜び

ではさっそく、特集を読みつつ試したことを中心に、Swift学習のまとめを書いていきます。

for-in文

リスト7にfor-in文のサンプルがありましたが、for-in文の中身が「a」だけなので、コメントの「"foo", "bar", "baz"をこの順で表示する」がよくわからず・・・
aを順々に取り出した値がitemなはずなので、おそらく本来はこんな感じだったのではないかと。

// データ集合処理
let a = ["foo", "bar", "baz"]
for item in a {
    println(item)   // aの要素を順に表示
}

playgroundで実行していると、コンソールを表示しないと「a」でも「println(item)」でも、 ループ内の結果は「3 times」としか表示されないので、ちょっと紛らわしいですね。

以下の、リスト14のコードでは、itemが活躍しているので、ここまで読むと使い方がイメージしやすいです。
ただ、誌上のコードだと「min = item < min ? item : mix」になっているので、そこだけ直してます。

/// 配列の最小値と最大値を一度に返す
func minmax(a: [Double]) -> (Double, Double) {
    var min = Double.infinity
    var max = -Double.infinity
    
    for item in a {
        min = item < min ? item : min
        max = item > max ? item : max
    }
    return (min, max)
}

ドキュメントコメント

Javadocコメントみたいなものですね。コメント形式もJavadocと同じですが、パラメータ名の説明等は書き方が違います。

/**
  * Javadocのような表記。
  * Option + クリックでドキュメントコメントの内容が参照できる
  * :param: paramName パラメータの説明
  * :returns: 返却値についての説明
  */

以下のような書き方もできます。これはちょっと気付かなかったですね。

///
/// ドキュメントコメントその2
/// ドキュメントコメントは///を続けた分だけ続く。
/// 先頭だけ///で、あとが//とかではダメ。
///

Javadocのように、説明コメントの形式が言語レベルで規定されているのは好感度高いです。

Optional

これは特にコード書きませんが、以前ブログで書いた、変数の後ろ?とかの話です。 以前は全く「?」と「!」の存在意義がわかりませんでしたが、この特集を読んだら少し理解出来ました。
あれですね、つまりnilチェックを円滑に行い、実行時エラーを出さないコードを書くときに、「?」を使うと綺麗に書けると。
で、「?」を実体化させて使うために「!」があるんだと、そういう理解になりました。
?がよくわからない人は是非、vol.84を買って読みましょう!

とはいえ、ハテナありきのコーディング・・・ある意味いつも通りさ!

ただちょっと、Optionalの束縛で使う糖衣構文は、使ってないと覚えられなそうです。。

// Optionalの束縛
if let x = "10".toInt() {    // 糖衣構文
    // xは非OptionalであるIntになる
    x
}

// ↑と同じ処理
let tmp = "10".toInt()
if tmp != nil {
    let x = tmp!
    x
}

そうそう、↑のコード例にもありますが、糖衣構文のところで宣言しているxは、 スコープもtmpを使った例と同じく、if文内だけになります。 「糖衣構文をnilチェックと実態を取り出すだけで使おう」とか考えても、 if文抜けたらスコープ切れるので注意が必要です。

??演算子

第3章のP31に、「右結合である演算子??を―」とありますが、さっぱりわからなかったので調べました。

nil結合演算子というようです。

この演算子は『左辺の値がnil以外なら左辺の値を、左辺がnilなら右辺の値を返す演算子』だそうです。 以下のコード例だと??演算子の評価後は、コメントの文字列が返却されます。

/// nil結合演算子の動作確認
let xa = "aaa"
let xb = "default"
let xc: String? = nil

xa ?? xb    // -> "aaa"
xc ?? xb    // -> "default"
参考

範囲演算子(言語による違い)

Swiftにも範囲演算子があります。これ、言語によってバラバラなので、覚えるのが大変です。。

言語 終了値含む 終了値含まない
Swift ... ..<
Groovy .. ..<
Ruby .. ...

これは・・・Ruby使いが混乱しそうですね。

でもこの演算子、Groovyでコード書いててもあまり使わないなぁ。 使いそうなところはクロージャで処理してしまうからか、Javaの癖が染み付いているからなのか。

Javaには範囲演算子がないので、範囲チェックなどは<=と<を使いますね。 他言語にもあるので、意味合いは同じです。

  • Java
    • x <= y:xはy以下(右辺値含む)
    • x < y :xはy未満(右辺値含まない)

import宣言や型の定義は文ではないようです。
Javaだとimport文というくらいなので、importも文ですが、Swiftはちょっと概念が違う模様。

for-in文の補足

for-inで要素を持つ入れ物(for item in aのitem)は定数。
変数ではないので再代入はできない。なので要素を変更するような処理には使えない。

ということはそういうことをやりたいときはクロージャ使うのかな?

switch文

caseが終わるとbreakがなくても終了する。
#break文自体はある。

これはこの仕様が良い気がしますね・・・breakをcaseの区切りのために入れるのは イケてない仕様だと思っていたので。Swiftではswitch文を使う機会が増えそうです。

だからなのか、サンプルでswitchを使っているコードが多かった気がします。

クロージャ式の書き方とか

型推論とかで省略できたりするので、使って覚えていかないとなぁと思っています。
以下に省略ありとなしを上げておきます(第3章のリスト4がベースです)。

/// 型推論で型付けしたクロージャ式
let a = ["banana", "apple", "cherry"]
a.sorted({a, b in return a < b})

// 省略しないで書く
a.sorted({(a: String, b: String) -> Bool in
    return a < b
})

省略解除はリスト3のクロージャ式のコードを参考にしたのですが、このクロージャ式の実行方法もちょっとわからなかったので補足コードをば。

// addの型は (Int, Int) -> Int
let add = { (a: Int, b: Int) -> Int in
    return a + b
}

add(2, 3)    // 関数のような書き方でクロージャを呼び出せる

Swift楽しい

結構長くなってしまったので、ここら辺で切り上げます。
今月号の記事だとFlywayのところも知りたかった内容なので、後ほど検証したいです。

しかし、今回もSwiftを勉強してみて、「簡単だな」とは思わないのですが、 「面白いな」とは改めて思いました。普段使ってる言語と違う仕様の言語で遊ぶのは楽しいですね。


誤記まとめ

本特集で見つけた誤記を以下にまとめておきます。

  • P27 リスト14中のfor-in文内

    • 誤:min = item < min ? item : mix
    • 正:min = item < min ? item : min
  • P33

    • 誤:リスト12 switc文の利用
    • 正:リスト12 switch文の利用
  • P45 リスト5中のa + [10, 20, 30]の結果

    • 誤:[10, 2, 3, 10, 20, 30]
    • 正:[1, 2, 3, 10, 20, 30]