構造体のスライス
[]Item で一覧を持つ
第5章では、商品一覧を3つの並びで持っていました。
Go
names := []string{"きのこ図鑑", "中古スマホ"}
prices := []int{1200, 24800}
categories := []string{"本", "家電"}構造体のスライスにすると、1つになります。
Go
items := []Item{
{Name: "きのこ図鑑", Price: 1200, Category: "本"},
{Name: "中古スマホ", Price: 24800, Category: "家電"},
}中の Item{...} は、型名を省略できます。[]Item と書いた時点で要素の型は決まっているからです。
添字のずれが起こりえない
3つの並びで持っていたときの危うさが消えます。
プレーンテキスト
並び3つ 長さがずれたら壊れる。どれが対応するか約束が暗黙
[]Item 1件が1つのまとまり。ずれようがない関数の引数も1つで済みます。
Go
func summary(items []Item) string // 第5章は引数4つだったrange で回す
Go
for _, item := range items {
total += item.Price
}読むだけならこれで十分です。
書き換えるときの落とし穴
第5章のクイズで触れた話が、ここで実害になります。
Go
for _, item := range items {
item.Price = 0 // 効かない
}range が渡してくる item はコピーです。構造体はコピーされる側なので、書き換えても元の一覧には届きません。
添字で指定すれば効きます。
Go
for i := range items {
items[i].Price = 0 // 効く
}Go を書いていて最も多い詰まりどころの1つです。 値レシーバの話と根は同じで、「コピーが渡っている」ことに気づけるかどうかにかかっています。
append も同じように使える
Go
var found []Item
for _, item := range items {
if item.Price < 1000 {
found = append(found, item)
}
}第5章で名前だけを集めていたところが、商品まるごとを集める形になります。集めた後も価格やカテゴリを参照できるので、こちらのほうが素直です。
要件
- 2つの並びから
[]Itemを組み立てる appendを使って要素を足すN件 合計M円 最高はCの形を返す- 0件のときは
該当なしを返す - 最高額が同じ商品が複数ある場合は、先に出てきたほうを採用する
入出力例
listSummary(["きのこ図鑑","中古スマホ","古い辞書"], [1200,24800,999]) → "3件 合計26999円 最高は中古スマホ"
listSummary(["高級品","安物"], [50000,100]) → "2件 合計50100円 最高は高級品"
listSummary(["きのこ図鑑"], [1200]) → "1件 合計1200円 最高はきのこ図鑑"
listSummary(["A","B"], [1000,1000]) → "2件 合計2000円 最高はA"ヒント
編集 ゆめさく編集部