10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

protocolを使ってenumが特定のcaseを持っていることを表す

Last updated at Posted at 2021-05-08

APIレスポンスをenumにマッピングする際、当てはまるものがなければunknownにしたい時がありました。
愚直に書くと以下のようになります。

enum Enum: String {
    case a
    case b
    case unknown
}

extension Enum {
    init(rawValue: RawValue) {
        self = Self(rawValue: rawValue) ?? .unknown
    }
}

しかし、以下のようなProtocolに準拠すると特定のcaseが存在することを明示的に表すことができます。

protocol HasUnknown, CaseIterable {
    static var unknown: Self { get }
}

enum Enum: String, HasUnknown {
    case a
    case b
    case unknown
}

そして、以下のようにprotocol extensionでinitを宣言しておけば、enumごとにマッピング処理を書く必要がなくなります。

extension HasUnknown where Self: RawRepresentable, RawValue: Equatable {
    init(rawValue: RawValue) {
        self = Self.allCases.first(where: { $0.rawValue == rawValue }) ?? .unknown
    }
}

以下のようにinitができます

let a = Enum(rawValue: "a") // case a
let unknown = Enum(rawValue: "others") // case unknown

Revision

2021/05/09 @takehito-koshimizu さんのアドバイスでマッピング処理がシンプルになり、CaseIterableに準拠する必要もなくなりました。ありがとうございます!

2021/05/11 と思いましたが、やはり既存で用意されているrawValueを使ったOptional initはコンパイルエラーは出ないものの、
実行時に無限ループとなりました。若干冗長ではありますがCaseIterableに準拠する必要があります。

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?