初期化とフィールド
3つの作り方
Go
// 1. フィールド名を指定する
item := Item{Name: "きのこ図鑑", Price: 1200, Category: "本"}
// 2. 順番に並べる
item := Item{"きのこ図鑑", 1200, "本"}
// 3. ゼロ値で作ってから入れる
var item Item
item.Name = "きのこ図鑑"1つ目を使ってください。 2つ目は短く書けますが、問題があります。
順番指定が壊れるとき
Go
type Item struct {
Name string
Price int
Category string
}
item := Item{"きのこ図鑑", 1200, "本"}ここで構造体にフィールドを1つ足すとします。
Go
type Item struct {
Name string
Stock int // 追加した
Price int
Category string
}さっきの行はコンパイルエラーになります。個数が合わないからです。
足すだけならエラーで気づけます。怖いのは並べ替えたときです。
Go
type Item struct {
Name string
Category string // Price の前に移した
Price int
}個数は変わっていないので、Item{"きのこ図鑑", 1200, "本"} は……と言いたいところですが、この場合は型が合わないのでやはりエラーになります。同じ型どうしを入れ替えたときだけ、エラーにならずに値が入れ替わります。Name と Category はどちらも文字列なので、この2つを入れ替えると商品名と分類が黙って逆になります。
フィールド名を書いておけば、順番も個数も関係ありません。
一部だけ指定できる
Go
item := Item{Name: "きのこ図鑑"}
// Price は 0、Category は ""書かなかったフィールドはゼロ値になります。エラーにはなりません。
便利ですが、書き忘れに気づけないという面もあります。第2章のゼロ値のところで触れた話が、そのまま構造体にも当てはまります。必須の項目がある型なら、後のレッスンでやる New 関数で守ります。
読み書き
Go
item.Name // 読む
item.Price = 1300 // 書くドットでたどります。入れ子になっていても同じです。
代入するとコピーされる
構造体は、配列と同じ側です。
Go
a := Item{Name: "きのこ図鑑"}
b := a
b.Name = "中古スマホ"
fmt.Println(a.Name) // きのこ図鑑 のままb は a のコピーなので、書き換えても a には影響しません。関数に渡したときも同じです。
Go
func rename(i Item) {
i.Name = "別の名前" // コピーを変えただけ
}この性質が、次の次のレッスンで扱うポインタレシーバの話につながります。書き換えたいのに反映されない、という詰まりどころの原因がここにあります。
要件
Item{Name: ..., Price: ...}の形でフィールド名を指定して作る- 値引き後の価格を
item.Priceに代入して更新する - 値引き後がマイナスになる場合は 0 にする
商品名 元の価格円 → 新しい価格円の形を返す
入出力例
applyDiscount("きのこ図鑑", 1200, 200) → "きのこ図鑑 1200円 → 1000円"
applyDiscount("きのこ図鑑", 1200, 0) → "きのこ図鑑 1200円 → 1200円"
applyDiscount("古い辞書", 800, 1000) → "古い辞書 800円 → 0円"
applyDiscount("おまけ", 500, 500) → "おまけ 500円 → 0円"ヒント
編集 ゆめさく編集部