Как прочитать данные из стандартного ввода (stdin) в консольном приложении на Go?
Использование bufio.Scanner для чтения строк
Ваша проблема — классическая для новичков в Go. fmt.Scan() действительно читает только до первого пробела, потому что он разбивает ввод по пробельным символам. Для чтения целых строк (с пробелами) лучше использовать bufio.Scanner из стандартной библиотеки.
Вот исправленная версия вашей программы:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Альтернатива: reader := bufio.NewScanner(os.Stdin)
fmt.Print("Введите имя: ")
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name) // Убираем символ новой строки и лишние пробелы
fmt.Print("Введите возраст: ")
ageStr, _ := reader.ReadString('\n')
ageStr = strings.TrimSpace(ageStr)
age, err := strconv.Atoi(ageStr) // Преобразуем строку в число
if err != nil {
fmt.Println("Ошибка: возраст должен быть числом")
return
}
fmt.Printf("Привет, %s! Тебе %d лет.\n", name, age)
}
Как это работает
bufio.NewReader(os.Stdin)создаёт буферизированный ридер для стандартного ввода.ReadString('\n')читает всё до символа новой строки (включительно).strings.TrimSpace()удаляет лишние пробелы и символ\nиз конца строки.strconv.Atoi()преобразует строку в целое число (int).
Альтернатива: bufio.Scanner
Другой популярный подход — использовать bufio.Scanner. Он удобнее, если нужно читать много строк:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Введите имя: ")
scanner.Scan()
name := scanner.Text()
fmt.Print("Введите возраст: ")
scanner.Scan()
ageStr := scanner.Text()
age, _ := strconv.Atoi(ageStr)
fmt.Printf("Привет, %s! Тебе %d лет.\n", name, age)
}
Scanner.Scan() читает следующую строку (до \n), а Text() возвращает её без символа новой строки.
Чтение чисел напрямую
Если вам нужно читать именно числа (без строк), можно использовать fmt.Scanf с форматированием:
var age int
fmt.Print("Введите возраст: ")
fmt.Scanf("%d\n", &age) // \n в конце — чтобы проглотить перевод строки
Но этот способ менее надёжен при смешанном вводе (строки и числа).
Почему ваша программа завершалась раньше времени?
Когда вы вводите "Анна 25", fmt.Scan(&name) читает только "Анна", а fmt.Scan(&age) пытается прочитать "25" из того же буфера. Если после числа остаётся символ новой строки, следующий Scan может прочитать пустую строку и завершиться с ошибкой. bufio.Scanner решает эту проблему, явно разбивая ввод по строкам.
Рекомендация
Для большинства консольных программ используйте bufio.Scanner — он простой, безопасный и хорошо обрабатывает разные типы ввода. Если нужна более сложная обработка (например, чтение больших объёмов данных), можно комбинировать с fmt.Scanf.
Чтение через fmt.Scanf и обработка ошибок
Если вы предпочитаете не использовать bufio, можно решить проблему с помощью fmt.Scanf и правильного форматирования. Этот метод хорошо подходит, когда заранее известен формат ввода (например, строка и число через пробел).
package main
import "fmt"
func main() {
var name string
var age int
fmt.Print("Введите имя и возраст через пробел: ")
// Читаем строку (до пробела) и число
_, err := fmt.Scanf("%s %d\n", &name, &age)
if err != nil {
fmt.Println("Ошибка ввода:", err)
return
}
fmt.Printf("Привет, %s! Тебе %d лет.\n", name, age)
}
Важно: %s читает только одно слово (до пробела). Если имя состоит из двух слов, используйте %q для строк в кавычках или переходите на bufio.
Использование bufio.Reader для построчного чтения
Для максимальной гибкости можно комбинировать bufio.Reader и fmt.Sscanf для разбора строк:
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Введите данные: ")
input, _ := reader.ReadString('\n')
var name string
var age int
fmt.Sscanf(input, "%s %d", &name, &age)
fmt.Printf("Имя: %s, Возраст: %d\n", name, age)
}
Этот подход даёт полный контроль над процессом: вы читаете сырую строку, а затем разбираете её как угодно (например, через strings.Split или регулярные выражения).
Ответов пока нет.
Войдите чтобы оставить ответ