Menu
Coddy logo textTech

ジェネリック関数

CoddyのSwiftジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 34/57。

ジェネリック関数は任意の型で動作します。山括弧内のプレースホルダー(多くの場合 T)は呼び出し側が使用する型を表し、Swift は各呼び出しでその型を補います。

func firstAndLast<T>(_ items: [T]) -> [T] {
    guard let first = items.first, let last = items.last else { return [] }
    return [first, last]
}

print(firstAndLast([3, 8, 1]))
print(firstAndLast(["a", "b", "c"]))

出力:

[3, 1]
["a", "c"]

関数の内部では T について何もわからないため、すべての型で機能する操作だけが許可されます。制約(T: Comparable など)を指定すると、より多くの操作が可能になります。ここでは < 演算子が使えます。

func largest<T: Comparable>(_ items: [T]) -> T? {
    guard var best = items.first else { return nil }
    for item in items where item > best { best = item }
    return best
}

print(largest([4, 9, 2])!)
print(largest(["pear", "apple", "zucchini"])!)

出力:

9
zucchini

ジェネリックは、Any とは異なり、正確な型を維持します。[Int] に対する largest の結果は Int? なので、キャストせずに算術演算で使用できます:

func largest<T: Comparable>(_ items: [T]) -> T? {
    items.max()
}

let top = largest([3, 7, 5]) ?? 0
print(top * 10)

出力:

70

関数には複数のプレースホルダーを含めることができ、制約では独自のプロトコルを指定できます。

protocol Scored { var score: Int { get } }
struct Player: Scored { let name: String; let score: Int }
struct Team: Scored { let score: Int }

func total<T: Scored>(_ items: [T]) -> Int {
    items.reduce(0) { $0 + $1.score }
}

func pair<A, B>(_ a: A, _ b: B) -> String { "\(a) & \(b)" }

print(total([Player(name: "a", score: 3), Player(name: "b", score: 4)]))
print(total([Team(score: 10)]))
print(pair(1, "one"))

出力:

7
10
1 & one
challenge icon

チャレンジ

簡単

任意の型の配列と述語 (T) -> Bool を受け取り、条件を満たす要素の数を返すジェネリック関数 countWhere(_:_:) と、任意の Hashable 型の配列を受け取り、最も頻繁に現れる要素(同数の場合は配列内で先に現れる要素)を返す mostCommon(_:) を記述してください。空の配列の場合は nil を返します。

提供されたコードは、カンマ区切りの単語の行と数値の行を読み取ります。そして、3文字より長い単語の数、最も頻繁に現れる単語、偶数の数、最も頻繁に現れる数値を出力します。

コードは Functions.swift に記述してください。main.swift には提供された入出力コードが含まれており、編集できません。

自分で試してみよう

// 提供された入出力コード: そのままにしておく
var input: [String] = []
while let line = readLine() { input.append(line) }
let words = input[0].split(separator: ",").map(String.init)
let numbers = input[1].split(separator: ",").map { Int($0)! }
print(countWhere(words) { $0.count > 3 })
print(mostCommon(words) ?? "none")
print(countWhere(numbers) { $0 % 2 == 0 })
print(mostCommon(numbers).map { String($0) } ?? "none")
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Swiftプレイグラウンド