SwiftUIの基本を身につけたい方はこちら

【Xcode/Swift】関数(func)の書き方について徹底解説〜Swift関数チートシート〜

この記事では、関数の基本的な使い方から、上級者向けの使い方まで解説していきたいと思います。

関数とは?

まず関数を簡単にいうと、処理をひとまとまりするものです。

例えば、以下のように3つのボタンが配置されていて、それぞれ押されたらcount1足して、printで「ボタンが押された。」と表示させています。

struct ContentView: View {
    @State var count = 0
    
    var body: some View {
        VStack {
            Text("\(count)")
            
            Button("追加ボタン1") {
                count += 1
                print("ボタンが押された。")
            }
            
            Button("追加ボタン2") {
                count += 1
                print("ボタンが押された。")
            }
            
            Button("追加ボタン3") {
                count += 1
                print("ボタンが押された。")
            }
        }
    }
}

これを関数を使って書くと、以下のように記述します。

struct ContentView: View {
    @State var count = 0
    
    var body: some View {
        VStack {
            Text("\(count)")
            
            Button("追加ボタン1") {
                buttonAction()
            }
            
            Button("追加ボタン2") {
                buttonAction()
            }
            
            Button("追加ボタン3") {
                buttonAction()
            }
        }
    }
    
    func buttonAction() {
        count += 1
        print("ボタンが押された。")
    }
}

このようにひとまとまりにすることで、コード量も減りますし、見やすくなりますし、さらに修正しやすくなります。

例えば、「ボタンが押された。」を、「ボタン押下」という文字に変更しようとした場合、関数を使っていない場合は、3箇所変えなければなりませんが、関数を使っている場合だと1箇所で済みます。ということは、関数を使うだけで、単純に修正時間が3倍速くなります。

ということで、関数の使い方を覚えると、コーディング力がグッと上がるので、この記事でしっかりと関数の使い方を覚えましょう。

関数の基本的な使い方

まず基本的な関数の使い方を解説します。

まずは、関数を定義します。

func xxx() {
    // ここに処理
}

書き方としては、funcをつけます。これは絶対必要です。次に、xxx()というように、xxxの部分にこの関数の名前をつけます。ここはできるだけわかりやすい名前をつけましょう。で、あとは{}でブロックを作って、その中に処理を書くだけです。

その次に、この関数の処理を実行したいときに、関数を呼びます。

ボタンなどのアクションなどの処理を行いたい場所で、xxx()というふうに記載してください。

Button("ボタン") {
    xxx()
}

これで処理が実行されます。

ちなみに、print()も関数の一つです。なぜ定義せずに使えるのかというと、Swiftがあらかじめ用意してくれているからです。

色々な関数の書き方

関数には色々な書き方があります。状況に応じて使い分けられるようになりましょう。

シンプルな関数

関数の定義

func greeting() {
    print("おはよう")
}

関数呼び出し

greeting() // "おはよう"

引数を使った関数

関数定義

func count(n: Int) {
    total += n
    print("\(n)を追加")
}

関数呼び出し

count(n: 10)

関数には引数ひきすうというのがあります。例えば、以下のようなプログラムがあったとしましょう。

struct ContentView: View {
    @State var totalAmount = 0
    
    var body: some View {
        VStack {
            Text("\(totalAmount)")
            
            Button("100円") {
                totalAmount += 100
                print("100円追加します。")
            }
            
            Button("50円") {
                totalAmount += 50
                print("50円追加します。")
            }
            
            Button("10円") {
                totalAmount += 10
                print("10円追加します。")
            }
        }
    }
}

100円ボタンを押したら、totalAmount100が追加され、"100円追加します。"と表示します。
50円ボタンを押したら、totalAmount50が追加され、"50円追加します。"と表示します。
10円ボタンを押したら、totalAmount10が追加され、"10円追加します。"と表示します。

というような簡単なプログラムです。

これを関数にしようとしたのですが、100円、50円、10円の部分がそれぞれ違うので、まとめることができません。。そのような時に引数を使います。

以下のように記述します。

struct ContentView: View {
    @State var totalAmount = 0
    
    var body: some View {
        VStack {
            Text("\(totalAmount)")
            
            Button("100円") {
                priceAddition(amount: 100)
            }
            
            Button("50円") {
                priceAddition(amount: 50)
            }
            
            Button("10円") {
                priceAddition(amount: 10)
            }
        }
    }
    
    func priceAddition(amount: Int) {
        totalAmount += amount
        print("\(amount)円追加します。")
    }
}

関数名の横に(amount: Int)というふうに記述します。amountは受け取る引数の名前です。Intは型名です。今回は数値なのでIntですが、文字列の場合はStringにします。

呼び出し時にそのamountに対して、値を渡します。

そうすることで、func内の処理中にamountを使うとそれぞれの値を使うことができ、処理をひとまとまりにできます。

呼び出し時の引数名を省略した関数

関数定義

func register(_ name: String, age: Int) {
    print("あなたの名前は\(name)さん")
    print("あなたの年齢は\(age)歳")
}

関数呼び出し

register("田中 太郎", age: 35)

関数定義の時に、引数の左がわに_をつけると、呼び出し時に値をそのまま書くだけで良くなります。

上記の例だと、名前は見ればわかるので省略しています。逆に数字は年齢かどうかというのがわからないので省略せずに記述しています。

もし、年齢も省略するなら以下の書き方になります。

func register(_ name: String, _ age: Int) {
    print("あなたの名前は\(name)さん")
    print("あなたの年齢は\(age)歳")
}
register("田中 太郎", 35)

必ず、順番は定義した引数の通りに記述してください。つまり、register(35, "田中 太郎")はダメです。

ちなみに、print()関数も関数呼び出しの値を省略していることになりますよね。

見てみると、_ intes: Anyというふうに呼び出しの引数を省略する形になっています。

関数内で引数を省略して使用する関数

関数定義

func area(height h: Int, width w: Int) {
    let area = h * w
    print("この四角形の面積は\(area)です。")
}

関数呼び出し

area(height: 10, width: 20)

引数名はなるべく分かりやすくした方が良いので、分かりやすくつけようとすると長くなってしまいます。長くなると関数内の計算などで使うときに大変なので、関数内で使用するときだけ省略した書き方にすることができます。

上記の例だと、heightwidthという引数名で、関数内で使うときは、その頭文字をとってhwです。引数が長くなってしまった場合や、その引数を関数内で何回も使うときなどに便利な関数です。

戻り値を使った関数

関数定義

func area(height: Int, width: Int) -> Int {
    let area = height * width
    return area
}

関数呼び出し

let result = area(height: 10, width: 20)
print("この四角形の面積は\(result)です") // この四角形の面積は200です

呼び出し時に、関数自身が値になるのがこの戻り値を使った関数です。戻り値というのは、上記の例で言うと、-> Intのことを指しています。

要は、area(height: 10, width: 20)自身が、計算結果のInt型の200になると言うことです。

->はおそらくを表しており、area(height: 10, width: 20)Intになるという感じです。

戻り値を使った場合は、必ずreturnでInt型の値を返さなければなりません。

return を省略した関数

関数定義

func area(height h: Int, width w: Int) -> Int {
    height * width
}

関数呼び出し

let result = area(height: 10, width: 20)
print("この四角形の面積は\(result)です") // この四角形の面積は200です

処理が1行の時のみreturnを省略できます。

非常に短く書けるので、以下のように関数を全て1行で書いたりします。

func area(height: Int, width: Int) -> Int { h * w }

オプショナル型の戻り値を使った関数

関数定義

func area(height: Int, width: Int) -> Int? {
    if height == 0 || width == 0 {
        return nil
    }
    return height * width
}

関数呼び出し

guard let result = area(height: 10, width: 20) { return }
print("この四角形の面積は\(result)です") // この四角形の面積は200です

戻り値の値に?をつけることで、nilreturnすることができるようになります。上記の場合だとheightwidhtのどちらかが0だった場合、nilを返しています。

呼び出しでは、nilになるので、オプショナルバインディングが必要になります。ちなみに戻り値に!をつけることもできます。

オプショナル型については以下の記事を参照してください。

【Swift】オプショナル型(Optional)について徹底解説~アンラップについても解説「!」「?」「??」、guard let、if let~

任意の数の引数を受け取る関数

関数定義

func sum(nums: Int ...) -> Int {
    var sum = 0
    nums.forEach {
        sum += $0
    }
    return sum
}

関数呼び出し

let result = sum(nums: 5, 3, 6, 7, 10)
print("合計は\(result)です") // 合計は31です

let result2 = sum(nums: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
print("合計は\(result2)です") // 合計は55です

同じ型の引数を任意の数にしたい場合は、関数定義時に、...を記述します。

そうすることで、呼び出し時に任意の数で指定できるようになります。

このような場合は、配列を使うので自分は使ったことはないですね。。

引数にデフォルト値をつける関数

関数定義

func register(name: String = "名無し", age: Int? = nil) {
    print("あなたの名前は\(name)さんです")
    print("あなたの年齢は\(name)歳です")
}

関数呼び出し

register()

引数は任意で使いたいと言うときに使えるのがこのデフォルト値をつける関数です。

上記の場合だと、呼び出し時に指定しなければ、nameには"名無し"ageにはnilが入ります。

引数で受け取った値を変更できる関数

関数定義

func swap(a: inout Int, b: inout Int) {
    let c = a
    a = b
    b = c
}

関数呼び出し

var a = 30
var b = 50

swap(a: &a, b: &b)

print(a) // 50
print(b) // 30

関数は、基本的に引数で受け取った値は変更できません。

しかし、上記のようにinoutをつけることで、関数内で引数の値を変更することができます。

上記のswap関数はaとbを入れ替える処理を行なっています。

呼び出し時には、値の前に&をつけなければなりません。

複数の戻り値を返す関数

関数定義

func BMI(tall: Double, weight: Double) -> (Double, Double) {
    let ideal = 22.0
    let t2 = tall * tall / 10000.0
    let index = weight / t2
    let target = ideal * t2
    return (index, target)
}

関数呼び出し

let result = bmi(tall: 175, weight: 68)
print("あなたのBMIは\(result.0)です。") // あなたのBMIは22.20408163265306です。
print("あなたの目標体重は\(result.1)です。") // あなたの目標体重は67.375です。

// ---もしくは---
let (bmi, target) = bmi(tall: 175, weight: 68)
print("あなたのBMIは\(bmi)です。") // あなたのBMIは22.20408163265306です。
print("あなたの目標体重は\(target)です。") // あなたの目標体重は67.375です。

複数の値を返したいときは、タプルを使いましょう。

上記の場合だと、戻り値でDouble型とDouble型のタプルを返しており、一つ目の値にはBMIの値を、二つ目の値には目標体重を入れています。

関数の呼び出し時には、resultと言う値にタプルを入れて、.0でBMIの値を取得、.1で目標体重を取得しています。もしくは、宣言時にlet (bmi, target) = というふうに記述することで、bmiでBMIの値を取得、targetで目標体重を取得することができます。二つ目の書き方の方がわかりやすいですね。

キーワード付きのタプルを返す関数

関数定義

func bmi(tall: Double, weight: Double) -> (index: Double, target: Double) {
    let ideal = 22.0
    let t2 = tall * tall / 10000.0
    let index = weight / t2
    let target = ideal * t2
    return (index, target)
}

関数呼び出し

let result = bmi(tall: 175, weight: 68)
print("あなたのBMIは\(result.index)です。") // あなたのBMIは22.20408163265306です。
print("あなたの目標体重は\(result.target)です。") // あなたの目標体重は67.375です。

戻り値の指定を、(index: Double, target: Double)というふうにキーワードをつけることで、呼び出し時、.index.targetで呼び出すことができます。

 

ネストされた関数

関数定義

func register(name: String) {
    func greeting() {
        print("\(name)さんこんにちは")
    }
    greeting()
}

関数呼び出し

register(name: "田中 太郎")

あまり使いませんが、関数はネストすることもできます。

評価