書いて覚えるSwift入門

第49回 Swift 5が来た!

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

Swift 5 has come

今回は当初予定ではSwiftとメモリ管理の話の続きを書く予定でしたが,3月25日にSwift 5がリリースされてしまったので急遽予定を変更し,Swift 5の話をすることにします。去年のWWDC 18 のWhat's new in Swift⁠early 2019⁠と予告されていたとおりですが図1)⁠筆者は今年は6月3日に開催されるWWDC19の寸前ぐらいだと憶測していたので少なからず驚いています。

図1 Swift 4から5へのロードマップ

図1 Swift 4から5へのロードマップ

Source Compatible w/Swift 4.x

では慌てる必要はあるかというと,実はほとんどありません。正しいSwift 4コードは正しいSwift 5コードでもあるからです。Swift 4とソースコード互換なのですから,既存のコードを直す必要はありません。この点において,Swift 5はSwiftの歴史の中で最も「大人しい」メジャーアップデートと言えるでしょう。

ABI frozen

ところが「節目」という意味では,これまでで最も大きなアップデートでもあるのです。なぜかというと,ABI(Application Binary Interface)が凍結されるからです。これがなぜ重要か。コンパイル済みのライブラリやモジュールを配布できるようになるからです。今まではソースコードごと配ってユーザにビルドしてもらう必要があったのがリンクするだけで使えるようになるというのは圧倒的な省資源省労力で,Cの完全上位互換だったはずのC++がCを置き換えられなかった最大の理由でもあります。

またこれにより,Swift 5で書かれたモジュールをSwift 6以降で使うことも可能になります。つまり,今まではObjective-Cで書かれていたFoundationなどの基幹モジュールもSwiftで書き直すことが容易になるということでもあり,実際そのようになっていくことと思われます。

#"Raw String"# at last!

Swift 5は前述のとおりSwift 4互換ですが,Swift 4ではありません。では何が違うのかというと,一番違うのはこれでしょう。筆者個人はこれだけでSwiftを5にする理由があるという立場です。

今までSwiftの文字列リテラル中のバックスラッシュ\は必ず文字エスケープとして解釈され,\そのものが多く出現する正規表現などを表記する際には\\を重ね書きする「お箸症候群」⁠chopstick syndrome)が不可避で,その一方でシングルクォート記号''がずっと未使用で,Perlのq()やRubyの%q()に相当する,バックスラッシュをエスケープしない「raw string」がいつ実装されるのかと心待ちにしていたのですが,Swiftはここでも最高の後出しジャンケンぶりを[SE-0200]で発揮してくれました。

let s0 = "\\n\n"
let s1 = #"\n\#n"#
s0 == s1 // true

おわかりいただけただろうか。つまり,#"でquote"。#でunquote。\#でescapeというしくみ。おもしろいのは#を複数重ねて##"でquote"。##でunquote。\##でescapeにもできること。Swift 4から導入済みの[SE-0168]"""#"""…"""#に対応しています。

let multiline = #"""
    だっ…誰があんたの事なんか
    いつもいつも変なこと言って
    すごく嫌われてるの判んないの!?
    きもち悪いわよ!!
    """#

驚くべきことに,5にいたってもまだ''(singlequote)`(backquote)は未使用のまま。驚くべき記号の節約ぶりです。

Result<Success,Failure:Error>

Swiftの例外処理は,例外をthrowする可能性のある函数をtryして,例外がthrowされたらcatchするというものです。

import Foundation

do {
    let u = URL(string:"https://example.com")!
    let s = try String(contentsOf: u)
    print(s)
} catch {
    print(error)
}

try?もあるので,catch不要の場合は次のようにもできます。

let u = URL(string:"https://example.com")!
if let s = try? String(contentsOf: u) {
    print(s)
}

しかし,例外をその場で処理するのではなく,成功失敗にかかわらず結果として扱いたい場合はどうすれば良いでしょう? [SE-0235]で追加され,Swift 5から標準装備となったResult型がその期待に応えてくれます。

let u = URL(string:"https://example.com")!
let r = Result { try String(contentsOf: u) }

Resultenumなので,次のようにして結果を取り出すことができます。

switch(r) {
case let .success(value):
    value
case let .failure(error):
    error
}

また.get()することで,do {} catch {}しなおすこともできます。

do {
    let s = try r.get()
    print(s)
} catch {
    print(error)
}

ExpressibleByStringInterpolation

Swiftの文字列展開(String Interpolation)では"\(expression)"expressionが文字化されて展開されます。これまではexpressionCustomStringConvertibleプロトコルに準拠している場合は.descriptionプロパティの値が,そうでない場合はSwiftが自動生成した値がそれぞれ使われていましたが,[SE-0228]により独自の文字列展開を定義できるようになりましたリスト1)⁠

リスト1 文字列展開サンプル

struct Point2D<T:Numeric> {
    var x:T
    var y:T
}

extension String.StringInterpolation {
    mutating func appendInterpolation<T:Numeric>(_ value: Point2D<T>) {
        appendInterpolation("(\(value.x), \(value.y))")
    }
}

let p = Point2D(x:3.0, y:4.0)
print(p) // "Point2D(x:3.0, y:4.0)"
print("\(p)") // (3.0, 4.0)

lessStringattached

Swift Blogの3月20日付記事にもあるとおり,Stringの内部実装がASCIIとUTF-16を切り替える方式から一元的にUTF-8を用いる方式に変わりました図2)⁠

図2 Stringの内部実装の変化

図2 Stringの内部実装の変化

これにより,たとえば.withCStringメソッドはわざわざCの文字列を生成する必要がなくなり,内部ポインタを返すだけでよくなったことで大幅なパフォーマンス向上を達成しました。

isMutiple(of:)

[SE-0225]が一部採用されたことにより,整数にisMultiple(of:)メソッドが追加されました。実装としては,

extension BinaryInteger { // 名前はわざと変えてある
    func isDivisible(by: Self)->Bool {
        return self % by == 0
    }
}

程度の簡単なものですが,英語的にはよりわかりやすいものとなっています。なお,もともとの提案にはisEvenおよびisOddもありましたが,現状ではisMultiple(of:)だけ定義されています。

令和はまだ未対応

リリースが3月25日だということからもわかるとおり,令和には未対応ですリスト2)⁠

リスト2 令和はまだ未対応

"\u{337E}".decomposedStringWithCompatibilityMapping // "明治"
"\u{337D}".decomposedStringWithCompatibilityMapping // "大正"
"\u{337C}".decomposedStringWithCompatibilityMapping // "昭和"
"\u{337B}".decomposedStringWithCompatibilityMapping // "平成"
"\u{32FF}".decomposedStringWithCompatibilityMapping // まだ"令和"じゃない!

以上駆け足でSwift 5を眺めていきましたが,ABIが凍結された一方,#""#のような後出しじゃんけんっぷりは健在で,まだまだevolutionは続けられそうです。次回は前回の続きから再開する予定です。

Software Design

本誌最新号をチェック!
Software Design 2019年7月号

2019年6月18日発売
B5判/192ページ
定価(本体1,220円+税)

  • 第1特集
    “速い”Webアプリケーションの作り方[バックエンド編]
    ボトルネックの見つけ方,キャッシュ・CDNの活用
  • 第2特集
    IT業界ビギナーのためのDocker+k8s入門講座[Kubernetes編]
    図解で深く理解して最先端にキャッチアップ!
  • 特別企画
    完全マネージ型のメリットを堪能する
    Amazon SageMaker入門
  • 特別企画
    クラウドへのルータ接続実践ノウハウ
    【2】AWSとヤマハルータをつなぐ
  • 一般記事
    「WebAuthn」が導く新時代のパスワードレス認証
    【後編】WebAuthnを利用したFIDO導入のための考え方
  • 短期連載
    Mattermost[導入+構築]入門
    【最終回】ご存じですか? chat導入のメリット

著者プロフィール

小飼弾(こがいだん)

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

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

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