在庫数の更新
CoddyのGOジャーニー「論理とフロー」セクションの一部 — レッスン 48/68。
チャレンジ
簡単包括的なバリデーションとエラーハンドリングを備えた在庫数更新機能を実装することで、在庫管理システムを強化しましょう。このチャレンジは、以前の機能をベースにしており、既存の製品数量を変更する機能を追加しつつ、在庫がマイナスになるような無効な操作を防止します。
2つの入力を受け取ります:
- 既存の在庫データを含む文字列。形式は
"product1:price1:quantity1,product2:price2:quantity2,product3:price3:quantity3"です(例:"Laptop:999.99:5,Mouse:25.50:15,Keyboard:75.00:8")。 - 在庫更新リクエストを含む文字列。形式は
"product1:change1,product2:change2,product3:change3"で、変更値は正または負の整数です(例:"Mouse:10,Tablet:-5,Keyboard:-3")。
あなたのタスクは以下の通りです:
- 以前のレッスンと同じ、
Price(float64) とQuantity(int) フィールドを持つProduct構造体を使用します。 - 最初の入力をカンマで分割して、個々の既存製品エントリを取得し、解析します。
- 各製品エントリをコロンで分割して、製品名、価格、数量を取得します。
- 価格の文字列を float64 に、数量の文字列を int に変換します。
- 既存の製品データを使用して
inventoryマップを作成し、データを格納します。 inventoryマップ、製品名、数量の変更値をパラメータとして受け取り、エラーを返すupdateStockという関数を作成します:- 製品が在庫に存在しない場合は、
"product not found: [product_name]"というメッセージとともにエラーを返します。 - 数量の変更によって在庫がマイナスになる場合(現在の数量 + 変更値 < 0)、
"insufficient stock: cannot reduce [product_name] by [absolute_change_value], only [current_quantity] available"というメッセージとともにエラーを返します。 - 更新が有効な場合は、在庫内の製品数量を修正し、nil を返します。
- 製品が在庫に存在しない場合は、
- 2番目の入力をカンマで分割して、在庫更新リクエストのリストを取得し、解析します。
- 各更新リクエストをコロンで分割して、製品名と数量の変更値を取得します。
- 数量の変更値の文字列を int に変換します。
- 更新プロセスのヘッダーを表示します:
"Processing Stock Updates:" - 各更新リクエストに対して
updateStock関数を呼び出し、結果を表示します:- エラーがなく、変更値が正の場合:
"[product_name]: Added [change] units - New stock: [new_quantity]" - エラーがなく、変更値が負の場合:
"[product_name]: Removed [absolute_change_value] units - New stock: [new_quantity]" - エラーがなく、変更値がゼロの場合:
"[product_name]: No change - Current stock: [current_quantity]" - エラーが発生した場合:
"[product_name]: Update failed - [error_message]"
- エラーがなく、変更値が正の場合:
- 更新の統計をカウントして表示します:
"Update Summary:""Updates processed: [total_number_of_updates_processed]""Updates successful: [number_of_successful_updates]""Updates failed: [number_of_failed_updates]"
- 更新された在庫を製品名のアルファベット順に表示します:
"Updated Inventory:"- 各製品について:
"- [product_name]: $[price] (Stock: [quantity])"
- 最終的な在庫統計を計算して表示します:
"Final Inventory Statistics:""Total Products: [total_number_of_products_in_inventory]""Total Items in Stock: [sum_of_all_quantities]""Total Inventory Value: $[sum_of_price_times_quantity_for_all_products]"
- 失敗した更新をリストアップします:
- 失敗した更新がある場合:
"Failed updates: [comma_separated_list_of_failed_product_names]" - 失敗した更新がない場合:
"All stock updates were processed successfully"
- 失敗した更新がある場合:
入力文字列の分割には strings パッケージ、文字列から数値への変換には strconv パッケージ、エラーメッセージの作成には errors パッケージ、フォーマットされた出力には fmt パッケージ、製品名のアルファベット順のソートには sort パッケージを使用してください。すべての価格と総在庫額は小数点以下2桁までフォーマットしてください。このチャレンジでは、包括的なバリデーションとエラーハンドリングを通じて、無効な操作を防ぎながら既存のデータを安全に修正する方法を学びます。
自分で試してみよう
package main
import (
"errors"
"fmt"
"sort"
"strconv"
"strings"
)
type Product struct {
Price float64
Quantity int
}
func addNewItem(inventory map[string]Product, productName string, price float64, quantity int) error {
if _, exists := inventory[productName]; exists {
return errors.New("product already exists: " + productName)
}
inventory[productName] = Product{Price: price, Quantity: quantity}
return nil
}
func main() {
var existingInventory string
var newProducts string
fmt.Scanln(&existingInventory)
fmt.Scanln(&newProducts)
inventory := make(map[string]Product)
// Parse existing inventory
existingItems := strings.Split(existingInventory, ",")
for _, item := range existingItems {
parts := strings.Split(item, ":")
name := parts[0]
price, _ := strconv.ParseFloat(parts[1], 64)
quantity, _ := strconv.Atoi(parts[2])
inventory[name] = Product{Price: price, Quantity: quantity}
}
// Parse new products to add
newItems := strings.Split(newProducts, ",")
fmt.Println("Adding New Items:")
itemsProcessed := 0
itemsAdded := 0
itemsRejected := 0
var rejectedProducts []string
for _, item := range newItems {
parts := strings.Split(item, ":")
name := parts[0]
price, _ := strconv.ParseFloat(parts[1], 64)
quantity, _ := strconv.Atoi(parts[2])
itemsProcessed++
err := addNewItem(inventory, name, price, quantity)
if err != nil {
fmt.Printf("%s: Failed to add - %s\n", name, err.Error())
itemsRejected++
rejectedProducts = append(rejectedProducts, name)
} else {
fmt.Printf("%s: Successfully added - $%.2f (Stock: %d)\n", name, price, quantity)
itemsAdded++
}
}
// Addition summary
fmt.Println("Addition Summary:")
fmt.Printf("Items processed: %d\n", itemsProcessed)
fmt.Printf("Items added: %d\n", itemsAdded)
fmt.Printf("Items rejected: %d\n", itemsRejected)
// Display updated inventory in alphabetical order
fmt.Println("Updated Inventory:")
var productNames []string
for name := range inventory {
productNames = append(productNames, name)
}
sort.Strings(productNames)
totalProducts := 0
totalItems := 0
totalValue := 0.0
for _, name := range productNames {
product := inventory[name]
fmt.Printf("- %s: $%.2f (Stock: %d)\n", name, product.Price, product.Quantity)
totalProducts++
totalItems += product.Quantity
totalValue += product.Price * float64(product.Quantity)
}
// Final inventory statistics
fmt.Println("Final Inventory Statistics:")
fmt.Printf("Total Products: %d\n", totalProducts)
fmt.Printf("Total Items in Stock: %d\n", totalItems)
fmt.Printf("Total Inventory Value: $%.2f\n", totalValue)
// List rejected products
if len(rejectedProducts) > 0 {
fmt.Printf("Rejected products: %s\n", strings.Join(rejectedProducts, ","))
} else {
fmt.Println("All new products were added successfully")
}
}