パターンマッチングはSwiftの基本的な機能であり、コードをより安全でクリーンにするものです。歴史的に、パターンマッチングは、特にassociated valuesを持つenumとのより表現力豊かで安全な操作手段として進化してきました。他の言語とは異なり、Swiftはif、guard、switchの式の中でネストされた値を直接アンラップすることを可能にします。
問題: 標準外のenum、特にネストされたassociated valuesを持つenumでは、caseの構造を誤ったり、主なswitchの制約を過小評価したりすることが容易です。また、if case、guard case、従来のswitchの使用における違いが明確でないことがよくあります。
解決策: シナリオに応じて異なるアプローチを用いると共に、複雑なネスト構造では明示的に名前を指定し、whereを使用することです。
コード例:
enum NetworkState { case success(User) case failure(Error, code: Int) case loading(progress: Double) } let state = NetworkState.failure(SomeError(), code: 401) if case let .failure(error, code) = state, code == 401 { print("Unauthorized: \(error)") } guard case .success(let user) = state else { return } print(user) switch state { case .success(let user): print("Welcome, \(user.name)") case .failure(let error, let code) where code == 404: print("Not Found: \(error)") case .failure(_, let code): print("Failure with code: \(code)") case .loading(let progress): print("Progress: \(progress)") }
主な特長:
switch内のすべてのcase enumを指定しないとどうなりますか?
コンパイルエラー(enumが非オプショナルな場合)または警告/デフォルトcaseの要件が発生します。Optionalsの場合は、.someと.noneだけを指定するだけで構いません。
ネストされたenumとassociated valuesに対してパターンマッチングを行うことはできますか?
はい。ただし、構文が複雑になります。ネストされた値に対しては、複数のレベルを一度にアンラップできます:
enum Outer { case inner(Inner) } enum Inner { case item(id: Int) } let e = Outer.inner(.item(id: 5)) if case let .inner(.item(id)) = e { print(id) }
guard caseとif caseの違いは何ですか?
guard caseは条件をチェックし、失敗した場合にはexitブロック(return、throw、break)を実行します。通常は要件に使用されます:一致しなかった場合は抜ける。
if caseは、関数からの退出なしでの1行条件処理に適した構文です。
開発者が複数のcaseを持つenumに対してswitchを使用し、新しいcaseをカバーしない。コードはコンパイルされるが、新しいシナリオが処理されず、アプリケーションがランタイムでクラッシュする。
利点:
欠点:
開発者がすべてのcaseを明示的にカバーし、ローカルフィルターのためにwhereを使用し、ネストされたletを通じてネストされた値をアンラップする。
利点:
欠点: