Swiftの引数ラベルが便利！for:変数名,with:変数名のように書ける！

:::note info
Swiftの「外部引数ラベル」と「内部引数名」が便利だったので記事にしました。
最適な引数ラベルを選ぶガイドラインも載せたので参考になればと思います。
:::

## Swiftの引数ラベルの便利さとその背景

### はじめに

KotlinとFlutterをやっていたのですが、最近Swiftエンジニアもやるようになりました。
そこで「引数ラベル」の使い方とその背景が面白かったので説明していきます。

### Swiftの引数ラベルとは？

多くのプログラミング言語では、関数の引数定義に引数名だけを使用し、関数を呼び出す際には引数名なしで値だけを渡します。しかし、Swiftの場合は「引数ラベル」という独特な仕様があります。この仕様により、関数を呼び出すときに引数の値の前にそのラベルを書く必要があります。

一見、面倒な仕様に思えますが、引数ラベルのおかげでコードの可読性が非常に向上し、関数が何をするのかがより明確になります。

### 引数ラベルと内部引数名の使い分け

Swiftでは、関数の引数に「外部引数ラベル」と「内部引数名」を指定することができます。これにより、関数を呼び出す際の可読性を高めつつ、関数内部ではわかりやすい変数名を使用することができます。

以下に、「外部引数ラベル」と「内部引数名」の例を示します。

```swift
func greet(for name: String, with message: String) {
    print("\(message), \(name)!")
}
```

この場合、`for`と`with`が外部引数ラベルであり、`name`と`message`が内部引数名です。
上記の関数を呼び出すときは、次のようになります。

```swift
func main() {
    greet(for: "Alice", with: "Hello")
}
```


外部引数ラベルを指定しない場合、引数名がそのまま外部引数ラベルとして使用されます。以下がその例です。

```swift
func greet(name: String, message: String) {
    print("\(message), \(name)!")
}

func main() {
    let name = "Alice"
    let message = "Hello"
    greet(name: name, message: message)
}
```

この場合、`greet`関数の呼び出し時に`name`と`message`を指定する必要があります。

外部引数ラベルを省略する場合は、アンダースコア（_）を使用します。

```swift
func greet(_ name: String, _ message: String) {
    print("\(message), \(name)!")
}

func main() {
    let name = "Alice"
    let message = "Hello"
    greet(name, message)
}
```

この場合、`greet`関数の呼び出し時に引数ラベルを指定する必要がありません。

### 引数ラベルの有無による見え方の違い

引数ラベルの有無によって、コードの可読性に大きな違いが生じます。以下に、具体例を示します。

#### 引数ラベルなし

```swift
struct Dice {
    private static let numbers: [Int] = Array(1...6)
    static func getNumber(index: Int) -> Int {
        numbers[index]
    }
}

let number = Dice.getNumber(index: 1)
print(number) // 2
```

引数ラベルがないため、呼び出し時に引数の意味がわかりにくい場合があります。

#### 引数ラベルを省略

```swift
struct Dice {
    private static let numbers: [Int] = Array(1...6)
    static func getNumber(_ index: Int) -> Int {
        numbers[index]
    }
}

let number = Dice.getNumber(1)
print(number) // 2
```

引数ラベルを省略すると、コードはコンパクトになりますが、引数の意味がさらにわかりにくくなります。

#### 引数ラベルあり

```swift
struct Dice {
    private static let numbers: [Int] = Array(1...6)
    static func getNumber(at index: Int) -> Int {
        numbers[index]
    }
}

let number = Dice.getNumber(at: 1)
print(number) // 2
```

引数ラベルを使用すると、コードの可読性が向上し、引数の役割が明確になります。

### 引数ラベルがSwiftに導入された背景

引数ラベルが導入された背景にはいくつかの理由があります。

1. **コードの可読性向上**:
    引数ラベルを使用することで、関数呼び出しの際に引数の役割が明確になり、コードの可読性が大幅に向上します。

2. **Objective-Cからの継承**:
    SwiftはObjective-Cとの互換性があり、Objective-Cではメソッド名が非常に長くなることが多々あります。これを解決するため、引数ラベルを用いることで簡潔かつ明確なメソッド呼び出しを実現しています。

3. **メソッドオーバーロードの防止**:
    引数ラベルを使用することで、同じ関数名でも異なるラベルを持つことで、異なる機能を持つ関数を定義することができます。これにより、メソッドオーバーロードの際の混乱を避けることができます。

### 特によく使われる引数ラベル

引数ラベルは柔軟に設定でき、関数の意図に応じて自由に選択できます。以下に、自分がよく使う引数ラベルとその用途を紹介します。

#### `for`

- **用途**: 特定の対象に対して操作を行う場合。
- **例**:

    ```swift
    func search(for query: String) {
        print("Searching for \(query)")
    }
    ```

#### `with`

- **用途**: あるものと一緒に操作を行う場合。
- **例**:

    ```swift
    func configure(with settings: [String: Any]) {
        print("Configuring with \(settings)")
    }
    ```

#### `at`

- **用途**: 特定の場所や時間を表す場合。
- **例**:

    ```swift
    func meet(at location: String) {
        print("Meeting at \(location)")
    }
    ```

### 引数ラベルが不要な場合

引数ラベルはコードの可読性を向上させますが、常に必要とは限りません。以下の場合には引数ラベルを省略することができます。

- **メソッド名が明確な場合**:

    ```swift
    func calculateSum(_ first: Int, _ second: Int) { }
    ```

- **引数の型が明確な場合**:

    ```swift
    func addItem(_ item: Item) { }
    ```

- **引数の役割が自然な場合**:

    ```swift
    func connectTo(destination: URL) { }
    ```

### 最適な引数ラベルを選ぶガイドライン

ここでは私の思う最適な引数ラベルを選ぶガイドラインを載せました。

1. **引数を区別できない場合**:
    全ての引数ラベルを省略します。例：`min(number1, number2)`, `zip(sequence1, sequence2)`。

2. **値を保持する型変換のイニシャライザ**:
    最初の引数ラベルを省略し、最初の引数は常に変換のソースであるべきです。例：`Int64(someUInt32)`。

3. **前置詞句の一部を構成する場合**:
    引数ラベルを付ける。通常、引数ラベルは前置詞で始まるべきです。例：`x.removeBoxes(havingLength: 12)`。

4. **単一の抽象化された部分を表す場合**:
    前置詞の後に引数ラベルを開始し、抽象化を明確にします。例：`a.fadeFrom(red: b, green: c, blue: d)`。

5. **最初の引数が文法句の一部を構成する場合**:
    引数ラベルを省略し、前の単語をベース名に追加します。例：`x.addSubview(y)`。

### まとめ

Swiftの引数ラベルは、コードの可読性と明確さを向上させます。
また、長いクラス名やメソッド名を簡潔に扱うために役に立ちそうです。
KotlinやFlutterにはないこの機能を活用することで、より直感的で保守しやすいコードを書くことができそうなので積極的に使っていこうと思います。

## 参考記事
https://www.swift.org/documentation/api-design-guidelines/