
fmt.Scanln 会截断首空格后的输入,导致 strings.Split 实际处理的字符串不含空格,切片长度不足而引发“index out of range”错误;应改用 bufio.Scanner 完整读取一行。
`fmt.scanln` 会截断首空格后的输入,导致 `strings.split` 实际处理的字符串不含空格,切片长度不足而引发“index out of range”错误;应改用 `bufio.scanner` 完整读取一行。
在 Go 中,strings.Split(s, " ") 本身完全正常——它总是返回 []string(字符串切片),但其结果是否符合预期,高度依赖输入字符串 s 的实际内容。问题根源不在 Split,而在 fmt.Scanln 对标准输入的处理方式。
fmt.Scanln 的行为是:按空白符(空格、制表符、换行)分词,并只读取第一个非空字段,随后立即丢弃该行剩余内容。例如,当用户输入 "2 3" 时,fmt.Scanln(&in) 仅将 "2" 赋值给 in,"3" 被静默忽略。因此 strings.Split(in, " ") 实际作用于 "2",返回 []string{"2"},访问 wh[1] 必然 panic。
✅ 正确做法:使用 bufio.Scanner 逐行完整读取输入:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
var seedCost float64
var lawnNo int
var in string
var area float64
var wh []string
scanner := bufio.NewScanner(os.Stdin)
// 读取 seedCost
scanner.Scan()
fmt.Sscanf(scanner.Text(), "%f", &seedCost) // 或用 strconv.ParseFloat
// 读取 lawnNo
scanner.Scan()
fmt.Sscanf(scanner.Text(), "%d", &lawnNo)
lawnCost := 0.00
for i := 0; i < lawnNo; i++ {
scanner.Scan()
in = scanner.Text() // ✅ 完整获取整行,如 "2 3"
wh = strings.Split(in, " ")
// 安全检查:确保至少有两个字段
if len(wh) < 2 {
fmt.Fprintf(os.Stderr, "警告:输入格式错误,期望至少两个数字,得到 %v\n", wh)
continue
}
w, err1 := strconv.ParseFloat(wh[0], 64)
h, err2 := strconv.ParseFloat(wh[1], 64)
if err1 != nil || err2 != nil {
fmt.Fprintf(os.Stderr, "解析错误:无法将 '%s' 或 '%s' 转为浮点数\n", wh[0], wh[1])
continue
}
area = w * h
lawnCost += area * seedCost
}
ans := strconv.FormatFloat(lawnCost, 'E', 8, 64)
fmt.Println(ans)
}? 关键要点:
-
fmt.Scanln≠ “读一行”,而是“读一个空白分隔的字段”; -
bufio.Scanner+scanner.Text()才是标准、可靠的一行读取方式; - 始终校验
strings.Split结果长度,避免越界; - 使用
strconv替代fmt.Sscanf可获得更清晰的错误反馈(推荐生产环境)。
通过切换输入方式并添加基础校验,即可彻底解决切片索引越界问题,让 strings.Split 发挥其本应具备的稳定分割能力。

















