Swiftの関数引数でラベルとinoutに詰まったときに見ること

Swiftの関数で、最初に引っかかりやすいのが引数ラベルです。

C++では基本的に位置で渡しますが、Swiftでは呼び出し側に名前が出ます。

公式でも、関数の各パラメータにはargument labelとparameter nameがあると説明されています。

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/#Function-Argument-Labels-and-Parameter-Names

引数ラベルが呼び出し側に出る

func move(from source: String, to destination: String) {
    print("\(source) -> \(destination)")
}

move(from: "src", to: "dst")

fromto は呼び出し側に出る名前です。

C++の感覚だと、こういうコメント付き呼び出しに近いかもしれません。

move(/* from */ "src", /* to */ "dst");

Swiftはこれを言語仕様として持っています。

外側と内側の名前を分けられる

Swiftでは、外部引数名と内部引数名を分けられます。

func move(from source: String, to destination: String) {
    print(source)
    print(destination)
}

呼び出し側は from / to、関数内部では source / destination を使います。

外から読みやすい名前と、中で扱いやすい名前を分けられるわけです。

_ でラベルを省略する

ラベルを出したくない場合は _ を使います。

func square(_ value: Int) -> Int {
    value * value
}

let result = square(4)

これはC++の普通の関数呼び出しに近いです。

auto result = square(4);

ただ、Swiftでは何でも _ にすると読みづらくなります。

resize(100, 200)

これだと幅と高さがどちらか分かりにくいです。

resize(width: 100, height: 200)

この方がSwiftらしい読みやすさになります。

inoutは参照渡しに近いが同じではない

Swiftで引数を書き換えたい場合は inout を使います。

func increment(_ value: inout Int) {
    value += 1
}

var count = 0
increment(&count)

C++の参照渡しに近い見た目です。

void increment(int& value) {
    value += 1;
}

ただしSwiftでは、呼び出し側で & が必要です。

increment(&count)

これは「ここで値が変更される」という印になります。

inoutを乱用しない

inout は便利ですが、Swiftでは戻り値で返す方が読みやすいことも多いです。

func incremented(_ value: Int) -> Int {
    value + 1
}

状態を直接変更する必要がある場合だけ inout にする、くらいでよさそうです。

まとめ

Swiftの関数引数は、C++より呼び出し側の読みやすさを強く意識しています。

  • 呼び出し側に引数ラベルが出る
  • 外部名と内部名を分けられる
  • _ でラベルを省略できる
  • inout は書き換える引数に使う
  • inout の呼び出し側には & が必要

Swiftでは、関数呼び出しが文章っぽく読めるかを意識すると書きやすいです。

参考