📚 Swift入門シリーズ: #16 guard文 → #17 オプショナル型
前回はオプショナル型による安全なnil処理を学びました。今回は、コードを再利用可能にする関数について学びましょう。
来春からデータサイエンティストとして働く予定の技術オタク。
『知りたい』気持ちで質問を止められない、好奇心旺盛な学生。
前回はオプショナル型でnilを安全に扱う方法を学んだね!
そうだね。今回からは、第7章:関数 について学んでいくよ。関数は、プログラムを整理して再利用可能にするための重要な機能なんだ。
関数って何?これまでも print() とか使ってきたけど、それも関数なの?
その通り!print() も関数なんだ。関数 は、特定の処理をまとめて名前を付けたもので、必要な時に呼び出して使えるんだよ。
関数とは
これまで、同じような処理を何度も書いてきたよね。例えば、こんなコードがあったとしよう。
// ユーザーAの挨拶
let nameA = "田中"
print("こんにちは、\(nameA)さん")
print("今日も良い一日を!")
// ユーザーBの挨拶
let nameB = "佐藤"
print("こんにちは、\(nameB)さん")
print("今日も良い一日を!")
// ユーザーCの挨拶
let nameC = "鈴木"
print("こんにちは、\(nameC)さん")
print("今日も良い一日を!")
同じようなコードを何度も書いているよね。これを 関数 にまとめることで、再利用できるようになるんだ。
それは便利そう!
関数の基本的な書き方
関数の基本的な書き方はこうなるよ。
func 関数名() {
// 処理
}
func は「function(関数)」の略なんだ。実際の例を見てみよう。
func greet() {
print("こんにちは")
print("今日も良い一日を!")
}
これで greet という名前の関数が定義できたんだ。
でも、これだけだと何も起きないよね?
その通り!関数を定義しただけでは実行されないんだ。関数を 呼び出す 必要があるんだよ。
func greet() {
print("こんにちは")
print("今日も良い一日を!")
}
// 関数を呼び出す
greet()
// こんにちは
// 今日も良い一日を!
greet() で関数を呼び出すと、関数の中の処理が実行されるんだ。
関数は何度でも呼び出せる
関数は何度でも呼び出せるんだよ。
func greet() {
print("こんにちは")
}
greet() // こんにちは
greet() // こんにちは
greet() // こんにちは
1回定義すれば、何度でも使えるんだ。これが関数の大きなメリットなんだよ。
パラメータ(引数)
でも、さっきの挨拶の例だと、名前を変えたいんだけど...
いい質問だね!関数に パラメータ(引数) を渡すことで、動的に値を変えられるんだ。
func greet(name: String) {
print("こんにちは、\(name)さん")
print("今日も良い一日を!")
}
(name: String) がパラメータなんだ。「String型のnameという値を受け取る」という意味だよ。
じゃあ、呼び出すときに名前を渡せばいいの?
その通り!
func greet(name: String) {
print("こんにちは、\(name)さん")
print("今日も良い一日を!")
}
greet(name: "田中")
// こんにちは、田中さん
// 今日も良い一日を!
greet(name: "佐藤")
// こんにちは、佐藤さん
// 今日も良い一日を!
greet(name: "鈴木")
// こんにちは、鈴木さん
// 今日も良い一日を!
同じ関数を使って、異なる名前で挨拶できるんだ。これで最初のコードがずっと短くなったね。
複数のパラメータ
パラメータは複数指定できるんだよ。
func greet(name: String, time: String) {
print("\(time)、\(name)さん")
}
greet(name: "田中", time: "おはようございます")
// おはようございます、田中さん
greet(name: "佐藤", time: "こんばんは")
// こんばんは、佐藤さん
カンマで区切って、複数のパラメータを定義できるんだ。
パラメータの順番は大事なの?
Swiftでは、パラメータ名を指定して呼び出すから、順番を間違えることは少ないんだ。でも、定義したパラメータ名と同じ名前で渡す必要があるよ。
func introduce(name: String, age: Int) {
print("私は\(name)です。\(age)歳です。")
}
introduce(name: "田中", age: 25)
// 私は田中です。25歳です。
// introduce(age: 25, name: "田中") // 順番を変えても動作するが、推奨されない
パラメータ名と引数ラベル
Swiftの関数には、引数ラベル と パラメータ名 という2つの名前があるんだ。
func greet(to name: String) {
print("こんにちは、\(name)さん")
}
greet(to: "田中")
to が引数ラベル(外部名)で、name がパラメータ名(内部名)なんだ。
- 引数ラベル: 関数を呼び出すときに使う名前
- パラメータ名: 関数の中で使う名前
引数ラベルを付けることで、関数の呼び出しが自然な英文のように読めるんだよ。
いつもこうしなきゃダメなの?
いや、引数ラベルを省略することもできるんだ。_(アンダースコア)を使うんだよ。
func greet(_ name: String) {
print("こんにちは、\(name)さん")
}
greet("田中") // 引数ラベルなしで呼び出せる
引数ラベルを _ にすると、呼び出し時に引数名を書かなくて良くなるんだ。
戻り値(return)
関数って、処理を実行するだけなの?計算結果を返したりできないの?
できるよ!関数は 戻り値 を返すことができるんだ。return を使うんだよ。
func add(a: Int, b: Int) -> Int {
return a + b
}
let result = add(a: 3, b: 5)
print(result) // 8
-> Int は「Int型の値を返す」という意味なんだ。return a + b で、計算結果を返しているよ。
これは便利!関数から値を受け取れるんだね!
そうなんだ。もう少し実用的な例を見てみよう。
func isAdult(age: Int) -> Bool {
if age >= 18 {
return true
} else {
return false
}
}
let age = 20
if isAdult(age: age) {
print("成人です")
} else {
print("未成年です")
}
// 成人です
Bool型を返す関数で、年齢が18歳以上かどうかを判定しているんだ。
この関数は、もっと短く書くこともできるよ。
func isAdult(age: Int) -> Bool {
return age >= 18
}
// さらに短く
func isAdult(age: Int) -> Bool {
age >= 18 // returnを省略できる
}
関数の本体が1行だけの場合、return を省略できるんだ。
複数の値を返す(タプル)
タプルを使えば、複数の値を返すこともできるんだ。
func getMinMax(numbers: [Int]) -> (min: Int, max: Int) {
var min = numbers[0]
var max = numbers[0]
for number in numbers {
if number < min {
min = number
}
if number > max {
max = number
}
}
return (min, max)
}
let result = getMinMax(numbers: [3, 7, 2, 9, 4])
print("最小値: \(result.min)") // 最小値: 2
print("最大値: \(result.max)") // 最大値: 9
タプルを使って、最小値と最大値を同時に返しているんだよ。
戻り値がない関数
戻り値がない関数は、戻り値の型を書かないか、-> Void と書くんだ。
// 戻り値の型を書かない(推奨)
func greet(name: String) {
print("こんにちは、\(name)さん")
}
// -> Void と明示的に書く
func greet(name: String) -> Void {
print("こんにちは、\(name)さん")
}
どちらも同じ意味なんだけど、通常は戻り値の型を書かない方が一般的だよ。
オプショナルの戻り値
関数の戻り値もオプショナルにできるんだ。
func findUser(id: Int) -> String? {
if id == 1 {
return "田中"
} else if id == 2 {
return "佐藤"
} else {
return nil
}
}
if let user = findUser(id: 1) {
print("ユーザー: \(user)")
} else {
print("ユーザーが見つかりません")
}
// ユーザー: 田中
if let user = findUser(id: 99) {
print("ユーザー: \(user)")
} else {
print("ユーザーが見つかりません")
}
// ユーザーが見つかりません
-> String? で、String型のオプショナルを返すことを示しているんだ。見つからない場合はnilを返せるんだよ。
デフォルト引数値
パラメータに デフォルト値 を設定できるんだ。
func greet(name: String, greeting: String = "こんにちは") {
print("\(greeting)、\(name)さん")
}
greet(name: "田中")
// こんにちは、田中さん
greet(name: "佐藤", greeting: "おはようございます")
// おはようございます、佐藤さん
greeting: String = "こんにちは" で、デフォルト値を設定しているんだ。呼び出し時に省略すると、デフォルト値が使われるんだよ。
これは便利!よく使う値をデフォルトにしておけるんだね!
関数の命名規則
関数名にも、命名規則があるんだ。
良い関数名:
- 動詞で始める(何をするかが分かる)
- 分かりやすく具体的にする
- キャメルケースを使う
// 良い例
func calculateTotal(price: Int, quantity: Int) -> Int {
return price * quantity
}
func isValidEmail(email: String) -> Bool {
return email.contains("@")
}
func printUserInfo(name: String, age: Int) {
print("\(name)さん(\(age)歳)")
}
悪い関数名:
// 悪い例
func calc(p: Int, q: Int) -> Int { // 短すぎる、意味不明
return p * q
}
func x(email: String) -> Bool { // 何をするか分からない
return email.contains("@")
}
func data(n: String, a: Int) { // 動詞がない、パラメータ名が不明瞭
print("\(n)さん(\(a)歳)")
}
実践練習
じゃあ、練習問題をやってみよう。
問題1: 2つの整数を受け取って、大きい方を返す関数 max を作ってみて。
やってみる!
func max(a: Int, b: Int) -> Int {
if a > b {
return a
} else {
return b
}
}
print(max(a: 5, b: 3)) // 5
print(max(a: 2, b: 8)) // 8
できた!
完璧だね!もっと短く書くこともできるよ。
func max(a: Int, b: Int) -> Int {
return a > b ? a : b
}
// さらに短く
func max(a: Int, b: Int) -> Int {
a > b ? a : b
}
三項条件演算子を使って、1行で書けるんだ。
すごい!短い!
問題2: 配列の中から偶数だけを抽出して新しい配列を返す関数 filterEvenNumbers を作ってみて。
func filterEvenNumbers(numbers: [Int]) -> [Int] {
var evenNumbers: [Int] = []
for number in numbers {
if number % 2 == 0 {
evenNumbers.append(number)
}
}
return evenNumbers
}
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let evens = filterEvenNumbers(numbers: numbers)
print(evens) // [2, 4, 6, 8]
こう?
素晴らしい!完璧だよ。配列を作って、偶数だけを追加して返しているね。関数の使い方をしっかり理解できているよ。
ちなみに、guardを使った書き方もできるよ。
func filterEvenNumbers(numbers: [Int]) -> [Int] {
var evenNumbers: [Int] = []
for number in numbers {
guard number % 2 == 0 else {
continue
}
evenNumbers.append(number)
}
return evenNumbers
}
どちらの書き方も正しいから、読みやすい方を選べばいいよ。
まとめ
この記事では、関数の基本について学びました。
関数の定義:
func 関数名() { 処理 }- 処理をまとめて名前を付ける
- 何度でも呼び出せる
パラメータ:
func 関数名(パラメータ名: 型) { 処理 }- 関数に値を渡せる
- 複数のパラメータも可能
- デフォルト値を設定できる
戻り値:
func 関数名() -> 型 { return 値 }- 計算結果を返せる
- オプショナルも返せる
- タプルで複数の値を返せる
- 1行の場合、returnを省略できる
命名規則:
- 動詞で始める
- 分かりやすく具体的に
- キャメルケースを使う
次回は「関数の引数」として、引数ラベル、可変長引数、inoutパラメータなど、さらに高度な関数の使い方を学びます!