書いて覚えるSwift入門

第24回 型の探求

この記事を読むのに必要な時間:およそ 4 分

From AP to Z

本題に入る前に臨時ニュースを。本連載第18回でも紹介したAPFSですが,iOS 10.3より正式導入が始まるようです。本記事執筆現在,iOS 10.3はまだβですが,OSアップデートすると同時にストレージがHFSXからAPFSにアップデートされます。本記事がみなさんのもとに届くころにはiOS 10.3とともにAPFSが我々のiPhoneやiPadに届いているかもしれません。

それよりずっと地味ながらも見落とせないのは,ZFSのmacOS向けオープンソース実装であるOpenZFS on OS XのSierra正式対応図1)⁠FreeBSDやLinuxといったほかのOpenZFS対応OSで作成されたストレージをMacから読み書きできるにとどまらず,なんと同じZFSプールから対応OSをマルチブートできてしまいます図2)⁠

図1 OpenZFS on OS X

図1 OpenZFS on OS X

図2 ZFSプールから対応OSをマルチブート

図2 ZFSプールから対応OSをマルチブート

すでにインストーラまでZFSに対応しているFreeBSD以外のOSのZFSブート環境構築はまだまだ面倒なのですが,これだけ毛色の異なるOSでファイルシステムがこのレベルで共通して使えることに,オープンソースというものの威力をあらためて実感しています。

オープンソースといえば,Swiftもそうでした。Swiftの父Chris LattnerのApple退社はSwift界隈で当然話題になりましたが,FreeBSDProjectの父Jordan HubbardもAppleに入社しその後退社しています。⁠父なき」あとも,両プロジェクトとも繁栄していることを鑑みれば,オープンソース化というのはプロジェクトのサバイヴァビリティ向上を大いに改善するのは確かなようです。あのMicrosoftですら,NadellaのCEO就任後はオープンソースへの態度を一変しているのも宜(むべ)なるかな。

型の集まりもまた型

ニュースはこれくらいにして本題に入りましょう。前回に引き続き今回も型の話です。今回は配列(array)や辞書(dictionary)のような,複数の値をまとめて扱うための「まとめ型」について,Arrayを例にとりながら学びます。

Swiftの型は静的。当然配列や辞書も静的な型を持つのですが,動的な型を持つ言語の配列や辞書に慣れていると,面食らうことが1つあります。

まずは,RubyとJavaScriptの配列を見てみましょう。

Rubyの例

% irb
irb(main):001:0> [nil,false,0,"",[],{}].each{¦e¦ p e.class}
NilClass
FalseClass
Fixnum
String
Array
Hash
=> [nil, false, 0, "", [], {}]

JavaScriptの例

% node
> [null,false,0,"",[],{}].forEach(function(e){console.log(typeof e)})
object
boolean
number
string
object
object
undefined
>

見てのとおり,配列型には異なる型の要素をなんでも入れることができます。なので配列自体の型は1種類で間に合います。

Swiftはどうでしょう?

図3のように文句を言われてしまいました。もう少し見ていきましょう。

図3 Swiftでの配列実験の結果

% swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
  1> [nil,false,0,"",[],[:]]
error: repl.swift:1:1: error: type of expression is ambiguous without more context
[nil,false,0,"",[],[:]]
  1> [false,true]
$R0: [Bool] = 2 values {
  [0] = false
  [1] = true
}
  2> [0,1]
$R1: [Int] = 2 values {
  [0] = 0
  [1] = 1
}
  3> ["","one"]
$R2: [String] = 2 values {
  [0] = ""
  [1] = "one"
}

そう。Swiftでは配列の要素の型はすべて同じで,そしてElementという要素の型を持つ配列の型は[Element]という型になるのです。

なんて型苦しい? ところでこのRubyコードを見てくれ。図4をどう思う?

図4 Rubyの実行結果

% irb
irb(main):001:0> ["answer",42,42.195,[true],false].each{¦e¦ p e + e}
"answeranswer"
84
84.39
[true, true]
NoMethodError: undefined method `+' for false:FalseClass
  from (irb):2:in `block in irb_binding'
  from (irb):2:in `each'
  from (irb):2
  from /usr/bin/irb:12:in `<main>'

すごく……大きなバグを誘発しそうな気がしませんか?

こういう場合,動的言語ではほとんどの場合,実行時に都度不正な値が入っていないかをチェックする,いわゆるvalidationで解決しています。たとえばこんな感じ。

% irb
irb(main):001:0> ["answer",42,42.195,[true],false].each do ¦e¦
irb(main):002:1* p e + e if e.respond_to?(:+)
irb(main):003:1> end
"answeranswer"
84
84.39
[true, true]
=> ["answer", 42, 42.195, [true], false]

しかしそれはその分コードの量が増えるということでもあり,増えたコードの分だけバグの可能性も増えるということでもあります。配列の要素の型が一定であれば,そうした心配はずっと減ります。

  1> [41,42].map{$0+$0}
$R0: [Int] = 2 values {
  [0] = 82
  [1] = 84
}
  2> [41.0,42.195].map{$0+$0}
$R1: [Double] = 2 values {
  [0] = 82
  [1] = 84.39
}
  3> ["answer","universe"].map{$0+$0}
$R2: [String] = 2 values {
[0] = "answeranswer"
  [1] = "universeuniverse"
}
  4> [false,true].map{$0+$0}
error: repl.swift:4:20: error: binary operator'+' cannot be applied to two 'Bool' operands
[false,true].map {$0+$0}

著者プロフィール

小飼弾(こがいだん)

1969年生まれ,東京都出身。元ライブドア取締役の肩書きよりも,最近はPokemon GOのガチトレーナーのほうが有名になりつつある……かもしれない永遠のエンジニアオヤジ。

活躍の場はIT業界だけでなく,サブカルからアカデミックまで多方面にわたり,ネットからの情報発信は気の向くまま毎日毎秒! https://twitter.com/dankogai,ニコニコチャンネルは,http://ch.nicovideo.jp/dankogai,blogはhttp://blog.livedoor.jp/dankogai/

当社刊行書籍は『小飼弾のアルファギークに逢ってきた』『小飼弾のコードなエッセイ』など。他にも著書多数。

コメント

コメントの記入