Menu
Coddy logo textTech

Mapの値としてのポインタ

CoddyのGOジャーニー「論理とフロー」セクションの一部。レッスン 27/68。

構造体をマップに直接格納することは便利ですが、構造体へのポインターを格納すると、強力な機能が利用できるようになります。それは、マップを通じて元の構造体データを直接変更できる機能です。この方法は、データを格納した後に更新する必要がある場合に不可欠です。

構造体へのポインターを map の値として格納すると、構造体のコピーではなく、構造体のメモリアドレスを格納することになります。このような map を宣言して操作する方法は次のとおりです。

type Product struct {
    Price    float64
    Quantity int
}

products := map[string]*Product{
    "laptop": &Product{Price: 999.99, Quantity: 5},
    "mouse":  &Product{Price: 25.50, Quantity: 20},
}

データを変更する必要があるときに、その主な利点が明確になります。ポインターを使っているため、map を通じて行った変更は元の struct に影響します。

// マップを通じてラップトップの価格を直接更新する
products["laptop"].Price = 899.99
fmt.Println(products["laptop"].Price) // 出力: 899.99

このパターンは、inventory システム、ユーザープロフィール、または map が主要なデータストアとして機能し、変更を保持する必要があるあらゆる状況など、保存されたデータを頻繁に更新する必要があるアプリケーションで特に有用です。

challenge icon

チャレンジ

簡単

map の値として構造体へのポインターを使用する強力さを示す、シンプルな在庫管理システムを作成してください。このチャレンジでは、ポインターを使った map によって保存されたデータを直接変更できるため、在庫システムを効率的にし、更新にすばやく対応できることを示します。

3つの入力を受け取ります:

  • 商品の数を表す文字列(例:"4"
  • 次の形式で商品データを含む文字列:"name1:price1:quantity1,name2:price2:quantity2,name3:price3:quantity3"(例:"laptop:999.99:5,mouse:25.50:20,keyboard:75.00:15,monitor:299.99:8"
  • 次の形式で更新操作を含む文字列:"operation1:product1:value1,operation2:product2:value2"。操作は "price" または "quantity" のいずれかです(例:"price:laptop:899.99,quantity:mouse:25,price:keyboard:65.00"

あなたの課題は次のとおりです:

  1. 次のフィールドを持つ Product 構造体を Define する:
    • Price(float64)- 商品の価格
    • Quantity(int)- 商品の在庫数
  2. キーが商品名(文字列)、値が Product 構造体へのポインターである map を Create する
  3. 2番目の入力から商品データを解析する:
    • 入力を commas で分割して、individual な商品 entries を取得する
    • 各 entry について、colons で分割し、名前、価格、数量を分ける
    • 価格の文字列を float64 に、数量の文字列を整数に Convert する
    • Product 構造体を Create し、その pointer を map に保存する
  4. 解析中、商品名を入力に現れる order のまま、別のスライスに保持する。Go で map を range するとキーがランダムな order で処理されるため、すべての一覧を入力 order に保つのはこのスライスです。
  5. "Initial Inventory:" というヘッダーで Initial 在庫を Display する
  6. 各商品を次の Format で表示する:"[name]: $[price] (Stock: [quantity])"
  7. 3番目の入力から更新操作を Parse して apply する:
    • 入力を commas で分割して、individual な operations を取得する
    • 各 operation について、colons で分割して、operation の種類、商品名、新しい値を取得する
    • map の pointer を通じて appropriate な field を directly 更新する
    • 各更新を次の Format で出力する:"Updated [product]: [field] changed to [new_value]"
  8. "Updated Inventory:" というヘッダーで更新後の在庫を Display する
  9. Initial の表示と同じ Format で各商品をもう一度表示する
  10. 在庫の合計値を Calculate して表示する:"Total Inventory Value: $[total_value]"

strconv package を使用して、価格と数量の文字列をそれぞれ対応する数値型に Convert してください。表示時には、すべての価格を小数点以下2桁に Format します。このチャレンジでは、map に pointer を保存すると元の構造体データを directly 変更できるため、map に値を再代入する必要なしに、在庫の更新を即座に反映し、その状態を維持できることを示します。

自分で試してみよう

package main

import (
	"fmt"
	"strconv"
	"strings"
)

func main() {
	// 入力を読み取る
	var numProductsStr string
	var productDataStr string
	var operationsStr string
	
	fmt.Scanln(&numProductsStr)
	fmt.Scanln(&productDataStr)
	fmt.Scanln(&operationsStr)
	
	// TODO: ここに Product 構造体を定義する
	
	// TODO: 商品ポインタを格納する map を作成する
	
	// TODO: 商品の順序を維持する slice を作成する(一貫した出力を確保するため)
	
	// TODO: 商品データを解析して map を埋める
	// 以下を忘れずに:
	// - productDataStr をカンマで分割して個々のエントリを取得する
	// - 各エントリについて、コロンで分割して name、price、quantity を取得する
	// - price と quantity の文字列を適切な型に変換する
	// - Product 構造体へのポインタを map に格納する
	// - 商品名を order slice に追加する
	
	// TODO: Display initial inventory
	// order slice を使用して商品を一貫して反復処理する
	// 形式: "[name]: $[price] (Stock: [quantity])"
	
	// TODO: 更新操作を解析して適用する
	// 以下を忘れずに:
	// - operationsStr をカンマで分割して個々の操作を取得する
	// - 各操作について、コロンで分割して type、name、value を取得する
	// - マップのポインタを通じて適切なフィールドを直接更新する
	// - 各操作の更新メッセージを出力する
	
	// TODO: Display updated inventory
	// 再度、一貫した出力のために order スライスを使用する
	// 表示しながら合計値を計算する
	
	// TODO: Calculate and display total inventory value
	// Format: "Total Inventory Value: $[total_value]"
}
quiz icon腕試し

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

論理とフローのすべてのレッスン

自分で練習してみよう: Goオンラインコンパイラ