Go语言如何读取用户输入并映射到结构体?新手求助
Go语言实现Python测试用例读取功能的修正方案
作为Go语言新手,我需要将一段Python代码的功能迁移到Go中:通过函数读取输入的测试用例,存储为结构体列表。当前编写的Go代码输出不符合预期,请求修正。
Python原代码功能
这段Python代码通过prepare_tests函数读取输入,将每个测试用例存储到namedtuple中,最终返回测试用例列表:
from collections import namedtuple from typing import List TestCase = namedtuple("TestCase", ["number_of_purchased_items", "prices"]) def prepare_tests() -> List[TestCase]: tests = [] cases_amount = int(input()) for _ in range(cases_amount): number_of_purchased_items = int(input()) prices = [int(price) for price in input().split(maxsplit=number_of_purchased_items + 1)] test_case = TestCase(number_of_purchased_items, prices) tests.append(test_case) return tests
输入示例
2 6 2 2 2 3 3 3 7 1 1 2 2 3 3 5
预期输出
[TestCase(number_of_purchased_items=6, prices=[2, 2, 2, 3, 3, 3]), TestCase(number_of_purchased_items=7, prices=[1, 1, 2, 2, 3, 3, 5])]
尝试的Go代码
package main import ( "bufio" "fmt" "os" "strconv" "strings" ) type testCase struct { numberOfPurchasedItems int prices []int } func prepareTests() []testCase { var tests []testCase scanner := bufio.NewScanner(os.Stdin) scanner.Split(bufio.ScanWords) scanner.Scan() casesAmount, err := strconv.Atoi(scanner.Text()) if err != nil { fmt.Println("Error:", err) return tests } for i := 0; i < casesAmount; i++ { scanner.Scan() numberOfPurchasedItems, err := strconv.Atoi(scanner.Text()) if err != nil { fmt.Println("Error:", err) return tests } scanner.Scan() pricesStr := scanner.Text() var prices []int for _, priceStr := range strings.Split(pricesStr, " ") { price, err := strconv.Atoi(priceStr) if err != nil { fmt.Println("Error:", err) return tests } prices = append(prices, price) } tests = append(tests, testCase{numberOfPurchasedItems, prices}) } return tests } func main() { fmt.Println(prepareTests()) }
当前错误输出
[{6 [2]} {2 [2]}]
问题分析
错误的核心原因是Scanner的分割方式设置错误:
- 代码中使用了
scanner.Split(bufio.ScanWords),这会将输入按空格/换行分割为单个单词(即单个数字)。 - 读取
numberOfPurchasedItems后,调用scanner.Scan()只能拿到单个价格数字,而非整行价格字符串,因此strings.Split(pricesStr, " ")只会得到一个元素。 - 后续循环会把下一个数字错误地当作新测试用例的
numberOfPurchasedItems,导致数据完全错位。
修正方案
方案1:按行读取(贴近Python逻辑)
恢复Scanner默认的按行分割行为,逐行读取输入,和Python的input()逻辑一致:
package main import ( "bufio" "fmt" "os" "strconv" "strings" ) type testCase struct { numberOfPurchasedItems int prices []int } func prepareTests() []testCase { var tests []testCase scanner := bufio.NewScanner(os.Stdin) // 读取测试用例数量 if !scanner.Scan() { fmt.Println("Failed to read cases amount") return tests } casesAmount, err := strconv.Atoi(scanner.Text()) if err != nil { fmt.Println("Error parsing cases amount:", err) return tests } for i := 0; i < casesAmount; i++ { // 读取购买商品数量 if !scanner.Scan() { fmt.Println("Failed to read number of items for case", i+1) return tests } numberOfPurchasedItems, err := strconv.Atoi(scanner.Text()) if err != nil { fmt.Println("Error parsing number of items for case", i+1, ":", err) return tests } // 读取价格行 if !scanner.Scan() { fmt.Println("Failed to read prices for case", i+1) return tests } priceStrs := strings.Fields(scanner.Text()) var prices []int // 确保只取指定数量的价格(和Python的maxsplit逻辑一致) for j := 0; j < numberOfPurchasedItems && j < len(priceStrs); j++ { price, err := strconv.Atoi(priceStrs[j]) if err != nil { fmt.Println("Error parsing price for case", i+1, ":", err) return tests } prices = append(prices, price) } tests = append(tests, testCase{numberOfPurchasedItems, prices}) } // 检查Scanner是否出现错误 if err := scanner.Err(); err != nil { fmt.Println("Scanner error:", err) } return tests } func main() { fmt.Println(prepareTests()) }
方案2:保持按单词分割(调整读取逻辑)
如果坚持使用ScanWords分割,需要循环读取numberOfPurchasedItems次来获取所有价格:
package main import ( "bufio" "fmt" "os" "strconv" ) type testCase struct { numberOfPurchasedItems int prices []int } func prepareTests() []testCase { var tests []testCase scanner := bufio.NewScanner(os.Stdin) scanner.Split(bufio.ScanWords) // 读取测试用例数量 if !scanner.Scan() { fmt.Println("Failed to read cases amount") return tests } casesAmount, err := strconv.Atoi(scanner.Text()) if err != nil { fmt.Println("Error parsing cases amount:", err) return tests } for i := 0; i < casesAmount; i++ { // 读取购买商品数量 if !scanner.Scan() { fmt.Println("Failed to read number of items for case", i+1) return tests } numberOfPurchasedItems, err := strconv.Atoi(scanner.Text()) if err != nil { fmt.Println("Error parsing number of items for case", i+1, ":", err) return tests } // 循环读取指定数量的价格 var prices []int for j := 0; j < numberOfPurchasedItems; j++ { if !scanner.Scan() { fmt.Println("Insufficient prices for case", i+1) return tests } price, err := strconv.Atoi(scanner.Text()) if err != nil { fmt.Println("Error parsing price", j+1, "for case", i+1, ":", err) return tests } prices = append(prices, price) } tests = append(tests, testCase{numberOfPurchasedItems, prices}) } if err := scanner.Err(); err != nil { fmt.Println("Scanner error:", err) } return tests } func main() { fmt.Println(prepareTests()) }
修正后输出
运行修正后的代码,输入示例数据会得到符合预期的输出:
[{6 [2 2 2 3 3 3]} {7 [1 1 2 2 3 3 5]}]
内容的提问来源于stack exchange,提问作者haku
相关产品推荐
相关产品推荐

