🍊

Swiftでクロージャの引数の意味を明確にしたい場合はタプルを使うと良い

2024/08/10に公開

Swiftでクロージャを使う際、呼び出し時に引数がどのように使われるかを明確にするために、引数にラベルをつけたいシーンがある。そういった場合は構造体やEnumを作成して対応していたが、タプルを使うことでよりシンプルに表現できる。

環境

Swift 5.10

引数ラベルがないクロージャの例

let action: ((Int, Int) -> Void) = { x, y in
    print(x, y)
}

action(1, 2)

上記のように、クロージャを呼び出す際に引数ラベルがないと、それぞれの引数がどのような意味を持つのか、どのように使われるのが分かりにくい。

以下のようには書けない。

// ❌ error: function types cannot have argument labels; use '_' before 'x'
let action: ((x: Int, y: Int) -> Void) = { x, y in
    print(x, y)
}

action(x: 1, y: 2)

構造体を使って引数の意味を呼び出し側へ明示する

引数にラベルをつける一つの方法として、構造体を使うことが考えられる。以下のように構造体を定義し、その型を使うことで引数の意味を明確にできる。

struct Option {
    let x: Int
    let y: Int
}

let action: ((Option) -> Void) = { option in
    print(option.x, option.y)
}

action(Option(x: 1, y: 2))

この方法でも機能するが、引数の個数が少ない場合、新たに構造体を定義するのはやや過剰なアプローチと感じる。そういった時は、タプルを使うとよりシンプルに解決できる。

タプルを使って引数の意味を呼び出し側へ明示する

タプルを使うと、構造体を使う時より少ないコード量で書ける。

let action: (((x: Int, y: Int)) -> Void) = { value in
    print(value.x, value.y)
}

action((x: 1, y: 2))

この方法では、タプル内の各要素にラベルを付けることで、クロージャを呼び出す際に引数の意味が明確になる。

タプルも型の一つ[1]のため、構造体などと同様にクロージャのパラメータの型に使えるのは当然といえば当然だ。

Appendix: Swift 3.0より前では引数ラベルを書くことができた

Swift 3.0より前のバージョンでは引数ラベルを書くことができたが、現在はサポートされていない。

https://github.com/swiftlang/swift-evolution/blob/main/proposals/0111-remove-arg-label-type-significance.md#proposed-solution

// Swift 3.0より前
let fn3 : (a: Int, b: Int) -> Bool

// Swift 3.0
let fn3 : (Int, Int) -> Bool
脚注
  1. https://docs.swift.org/swift-book/documentation/the-swift-programming-language/types/#Tuple-Type ↩︎

Discussion