Swiftの学習を始めるにあたって、最初に公式のチュートリアル「iOS向けAppの開発」を行いました。
勉強している中で、こんな文が出てきてぱっと見イミわからん😵💫となりました。
self.attendees = attendees.map { Attendee(name: $0) }
調べてみたところ、無事理解したので、そのアウトプットも兼ねて記事を作成しました。
結論から言うとこのコードは既存のコレクション内の各要素を反復して変換を適用することにより、新しいコレクションを作成するものです。
ただ言葉で表すとわかりにくいと思うので、コードと共に例を挙げて順に説明していきます。
struct DailyScrum: Identifiable {
let id: UUID
var attendees: [Attendee]
init(id: UUID = UUID(), attendees: [String], ) {
self.id = id
self.attendees = attendees.map { Attendee(name: $0) }
}
}
extension DailyScrum {
struct Attendee: Identifiable {
let id: UUID
var name: String
init(id: UUID = UUID(), name: String) {
self.id = id
self.name = name
}
}
}
コードの全体像はこんな感じになります。DailyScrum構造体と、それを拡張して作成したAttendee構造体が定義されています。(説明を簡潔化するため、元のコードと変えている部分があります)
まず、DailyScrumがインスタンス化されるところから始まります。今回は引数として、たろう,じろう,さぶろうの配列を渡しました。
var dailyScrum = DailyScrum(atendees: ["たろう", "じろう", "さぶろう"])
インスタンス化される時、initが呼ばれ、変数に値が格納されます。
init(id: UUID = UUID(), attendees: ["たろう", "じろう", "さぶろう"]) {
self.id = id
self.attendees = attendees.map { Attendee(name: $0) }
}
このとき、例の式が出てきます。右辺で何が起こっているのでしょうか。
引数attendeesに対してmapメソッドが使われています。
["たろう", "じろう", "さぶろう"].map { Attendee(name: $0) }
mapメソッドは配列の中身に全て同じ処理をしたいときに使われます。例えば、全員にさんをつけて["たろうさん", "じろうさん", "さぶろうさん"]
という配列に変換したいときに使えます。
どのような処理をしたいかが後ろの{ Attendee(name: $0) }
になります。
{}で囲まれた処理はクロージャと言ってブロックで囲んだ中にある処理を実行する自己完結型の機能です。
Attendee(name: $0)
クロージャの中のこの式はAttendeeクラスをインスタンス化しています。
DailyScrum(atendees: ["たろう", "じろう", "さぶろう"])
このDailyScrumクラスをインスタンス化するのと同じような操作と考えるとイメージがつきやすいです。
そして、最大の謎がname: $0
これですよね。nameプロパティの引数として、渡されている$0
、これは一体何なのでしょうか?
ヒントはクロージャの省略にあります。クロージャーは省略なしだと、以下のような形をとります。
{ (引数) -> 戻り値の型 in
処理
}
なので、今回の例だと、
{ (name) -> Attendee in
Attendee(name: name)
}
引数nameを受け取って、そのnameでAttendeeインスタンスを作成するという操作を行なっています。
クロージャは戻り値の型を省略できます。その結果以下のようになります。
{ name in
Attendee(name: name)
}
さらに引数自体(inも)も省略することができます。このとき、使いたい一つ目の引数を$0
二つ目の引数を$1
以下同様、、として使うことができます。つまり、、
{ Attendee(name: $0) }
あの最初に見た形になりましたね!私がわからん😵💫となった$0はクロージャによって省略された第一引数でした。
それがmapで繰り返し処理されるので、結果的にこのような新しい配列が作成されます。
[Attendee(name: "たろう"), Attendee(name: "じろう"), Attendee(name: "さぶろう")]
その配列がself.attendees
つまり、DailyScrumインスタンスのattendeesという変数に格納されます。
結果的にこのようなインスタンスが作成されることになります。
var dailyScrum = DailyScrum(
attendees:
[
Attendee(name: "たろう"),
Attendee(name: "じろう"),
Attendee(name: "さぶろう")
]
)
つまり、既存のコレクション["たろう", "じろう", "さぶろう"]
はただの文字列の配列でしたが、mapを使って変換することにより、上記のようなAttendeeインスタンスの配列にすることができました。
mapとクロージャの省略を使うことでコレクションの変換を容易にすることができます。超長々と解説してしまいましたが、すごく長ったらしく丁寧に説明したので、同じところで詰まった人の手助けになれば幸いです。
参考: https://developer.apple.com/tutorials/app-dev-training
出てきた箇所:5章Creating a navigation hierarchy、4節Creating a navigation hierarchy