Получение данных от пользователя
Программы без ввода скучные. Разберём все способы получения данных: от простого fmt.Scan до полноценного CLI.
fmt.Scan - самый простой способ
package main
import "fmt"
func main() {
var name string
fmt.Print("Как тебя зовут? ")
fmt.Scan(&name)
fmt.Println("Привет,", name)
}
&name - это указатель на переменную. Scan записывает значение по этому адресу.
Несколько значений
var name string
var age int
fmt.Print("Имя и возраст: ")
fmt.Scan(&name, &age) // ввод через пробел: Alice 30
fmt.Printf("%s, %d лет\n", name, age)
fmt.Scanf - с форматом
var hours, minutes int
fmt.Print("Введи время (ЧЧ:ММ): ")
fmt.Scanf("%d:%d", &hours, &minutes)
fmt.Printf("Через час будет %d:%02d\n", hours+1, minutes)
bufio.Scanner - чтение строк
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Введи полное имя: ")
scanner.Scan()
name := scanner.Text()
fmt.Println("Привет,", name) // "Иван Петров" - целиком
}
Чтение нескольких строк
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("Введи заметки (пустая строка = конец):")
var notes []string
for scanner.Scan() {
line := scanner.Text()
if line == "" {
break
}
notes = append(notes, line)
}
fmt.Printf("Записано %d заметок\n", len(notes))
Обработка ошибок ввода
Про strconv.Atoi и преобразование строк в числа - урок Преобразование типов и strconv. Про возврат error и его обработку - урок Обработка ошибок как философия.
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Введи число: ")
scanner.Scan()
text := scanner.Text()
num, err := strconv.Atoi(text)
if err != nil {
fmt.Println("Это не число:", text)
return
}
fmt.Println("Твоё число:", num)
Аргументы командной строки - os.Args
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Программа:", os.Args[0])
if len(os.Args) < 2 {
fmt.Println("Использование: program <имя>")
return
}
name := os.Args[1]
fmt.Println("Привет,", name)
}
go run main.go Alice
# Привет, Alice
Пакет flag - удобные CLI-флаги
package main
import (
"flag"
"fmt"
)
func main() {
name := flag.String("name", "World", "имя для приветствия")
count := flag.Int("count", 1, "сколько раз поздороваться")
loud := flag.Bool("loud", false, "КАПСОМ")
flag.Parse()
for i := 0; i < *count; i++ {
greeting := fmt.Sprintf("Привет, %s!", *name)
if *loud {
greeting = fmt.Sprintf("ПРИВЕТ, %s!", *name)
}
fmt.Println(greeting)
}
}
go run main.go -name=Alice -count=3 -loud
# ПРИВЕТ, Alice!
# ПРИВЕТ, Alice!
# ПРИВЕТ, Alice!
go run main.go --help
# Usage:
# -count int сколько раз поздороваться (default 1)
# -loud КАПСОМ
# -name string имя для приветствия (default "World")
<ComparisonTable data={{ headers: ["Способ", "Когда", "Пример"], rows: [ ["fmt.Scan", "Простой интерактивный ввод", "Калькулятор, опросник"], ["bufio.Scanner", "Строки с пробелами, многострочный ввод", "Чат, заметки, CSV"], ["os.Args", "Простые аргументы CLI", "program file.txt"], ["flag", "CLI с флагами и описанием", "server -port=8080 -debug"] ] }} />
Практический пример: мини-калькулятор
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("Калькулятор. Формат: число оператор число")
fmt.Println("Пример: 10 + 5")
fmt.Println("Для выхода введи: exit")
for {
fmt.Print("> ")
scanner.Scan()
input := scanner.Text()
if input == "exit" {
break
}
parts := strings.Fields(input)
if len(parts) != 3 {
fmt.Println("Ожидаю: число оператор число")
continue
}
a, err := strconv.ParseFloat(parts[0], 64)
if err != nil {
fmt.Println("Первый аргумент не число")
continue
}
b, err := strconv.ParseFloat(parts[2], 64)
if err != nil {
fmt.Println("Второй аргумент не число")
continue
}
switch parts[1] {
case "+":
fmt.Printf("= %.2f\n", a+b)
case "-":
fmt.Printf("= %.2f\n", a-b)
case "*":
fmt.Printf("= %.2f\n", a*b)
case "/":
if b == 0 {
fmt.Println("Деление на ноль!")
} else {
fmt.Printf("= %.2f\n", a/b)
}
default:
fmt.Println("Неизвестный оператор:", parts[1])
}
}
}