Appleが2014年にオリジナルリリースしたプログラム言語のSwiftが、バージョン5.2に到達した。Xcode 11.4 Betaで使用可能なSwift 5.2は、品質とパフォーマンスの大幅な向上を目指して設計されたリリースだ。Swift Evolutionプロセスに従った今回のバージョンでは、callAsFunctionの導入、デフォルトパラメータ付きサブスクリプト(subscript)、Key Path Expressions as Functions、新しくなった診断アーキテクチャなどが提供されている。
Swift 5.2のcallAsFunction()
あるいは"Callable values of user-defined nominal types"では、静的に呼び出し可能な値がSwiftに導入される。Callable valueは関数的な振る舞いを定義した値(value)で、関数コールの構文を使って呼び出すことができる。この機能では、パラメータラベルとパラメータ型、throwとrethrowがサポートされており、プライマリのタイプ宣言に制約はない。ひとつのタイプに複数のcallAsFunction
メソッドを宣言することも可能で、この場合はSwiftが、単純なオーバーロードと同じように呼び出し対象を処理してくれる。
struct Adder {
var base: Int
func callAsFunction(_ x: Int) -> Int {
return base + x
}
}
let add3 = Adder(base: 3)
add3(10) // returns 13, same as adder.callAsFunction(10)
サブスクリプトはコレクションやシーケンス、あるいはリストのメンバ要素にアクセスするためのショートカットで、クラスや構造体、列挙(enumeration)内で定義することができる。サブスクリプトを使用することで、値を設定するためのメソッドと取得するためのメソッドを書かなくても、インデクスによる設定と取得ができるようになる。Swift 5.2では、任意のタイプのパラメータにデフォルト値を持ったサブスクリプトを追加できるようになった。以下のコードスニペットで示したBucketList
構造体では、範囲外のインデックスで読み込みを実行した場合にデフォルト値を返している。
struct BucketList {
var items: [String]
subscript(index: Int, default: String = "your list is over") -> String {
if index >= 0 && index < items.count {
return items[index]
} else {
return `default`
}
}
}
let bucketList = BucketList(items: ["travel to Italy", "have children", "watch super bowl")
print(bucketList[0])
print(bucketList[4])
このコードでは、後者のインデックス値4に対応する値がないため、"travel to Italy"に続いて"your list is over"が表示される。
"Key Path Expressions as Functions"は、(Root)->Value
という関数に\Root.value
というキーパス式が使用可能になる機能を導入する。次のようなUser
構造体を考えてみよう。
struct User {
let email: String
let isActive: Bool
}
この構造体を使ったユーザの配列が事前に用意されているものとする。ユーザのリストを取得するには、キーパス機能以前であれば、users.map { $0.emal }
としてEメールのリストを収集したり、同様にusers.filter { $0.isActive }
でアクティブなユーザの配列を取得するなどしていた。
キーパスを使用することで、users.map(\.email)
を適用してEメールの配列を収集したり、users.map{ $0[keyPath:\User.isActive] )を使用して
アクティブなっユーザの一覧を取得することが可能になる。
Swift 5.2にはさらに、開発者が何らかのコーディングミスをした場合のエラーメッセージの質と正確性を改善するように設計された、新しい診断アーキテクチャが導入されている。新しい診断アーキテクチャよりも正確性に劣る以前の診断の例と、それがSwift 5.2でどのようになったのかを確認しよう。
Invalid Optional Unwrap
struct S { init(_: [T]) {} } var i = 42 _ = S([i!])
これには従来、"error: type of expression is ambiguous without more context
"というエラーが出力されていたが、新バージョンでは"error: cannot force unwrap value of non-optional type 'Int' _ = S<Int>([i!]) ~^
"と判定されるようになった。
Argument-to-Parameter Conversion Mismatch
import SwiftUI struct Foo: View { var body: some View { ForEach(1...5) { Circle().rotation(.degrees($0)) } } }
これまでは"error: Cannot convert value of type '(Double) -> RotatedShape<Circle>' to expected argument type '() -> _'
"と判断されていたが、これが"error: cannot convert value of type 'Int' to expected argument type 'Double' Circle().rotation(.degrees($0)) ^ Double( )
"と報告されるようになった。
その他、Swift 5.2とは直接的な関連はないが特筆に値する機能として、以下のようなものがある。
- Xcode 11.4ベータでは、ユニバーサル購入(universal purchase)としてのmacOSアプリの構築と配布がサポートされるようになった。Xcode 11.4で開発された新しいMac Catalystアプリは、既定値としてユニバーサル購入が有効になる。
- ビルド設定の新たな評価オペレータとして
default
が追加された。"$(SETTING:default=someting)
"のように定義することで、評価時のコンテキストにおいてnilと評価された場合のビルド設定として、デフォルト指定値を参照することが可能になる。 - ツールバージョン5.2以降を使用したRemote Swiftパッケージでは、テストターゲットのみで使用されるパッケージの依存関係の解決を行わないようになった。これによってパフォーマンスが向上し、依存関係のバージョン干渉に関するリスクが低減する。
新機能とバグ修正、既知の問題に関する完全なリストは、Xcode 11.4ベータ版のリリースノートに記載されている。