You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 11:55:40