LoginSignup
16
14

More than 1 year has passed since last update.

[Swift] Enumの意外に知られてない性質

Posted at

今回はEnumの意外に知られていない性質についてご紹介していきます。

enumのcaseはprotocolで定義することができる

実はcaseはprotocolで定義することができます。これはSwift5.3で追加された機能です。
このようにして定義します。

protocol EnumProtocol {
    static var foo: Self { get }
    static func hoge(arg: Int) -> Self
    static func fuga(arg1: Int, arg2: String) -> Self
}

enum Hoge: EnumProtocol {
    case foo
    case hoge(arg: Int)
    case fuga(arg1: Int, arg2: String)
}

associated valueがないcaseは、

static var foo: Self { get }

associated valueがあるcaseは、

static func hoge(arg: Int) -> Self

このように、caseをprotocolで定義することができました。

enumはクロージャで表せる

enumのcaseはクロージャで表すことができます。
ただし、クロージャで表せるのはassociated valueを使っているcaseのみとなります。

let foo: () -> Hoge = Hoge.foo // ❌
let hoge: (Int) -> Hoge = Hoge.hoge // 🟢
let fuga: (Int, String) -> Hoge = Hoge.fuga // 🟢

正直、どこでつかうねんという感じですが、
この性質を利用して作られた、swift-case-pathsというライブラリがあります。
詳しい説明は省きますが、KeyPathと同じ感じで、このようなことができるようになったりするライブラリです。

let hoges: [Hoge] = [.foo, .hoge(arg: 2), .fuga(arg1: 1, arg2: 2)]
hoges.map(/Hoge.hoge)
// [.hoge(arg2: 2)]

swift-case-pathsの/オペレーターの定義はこのようになっています。

public prefix func / <Root, Value>(
  embed: @escaping (Value) -> Root
) -> CasePath<Root, Value> {
  .init(embed: embed, extract: extractHelp(embed))
}

(Value) -> Root
でcaseをクロージャで受け取っていることがわかると思います。
正直内部実装はあまり理解していないので解説はできないのですが、こういうところで使われているんだなー程度に思っていてください。

まとめ

protocolでenumのcaseを定義できるのは便利ですね。
ただ、closureで定義できる性質は使い道が思い浮かんでいないので、面白い使い方を見つけたいですね。

16
14
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
16
14