Получение данных от пользователя

Программы без ввода скучные. Разберём все способы получения данных: от простого 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)
`fmt.Scan` читает до пробела или переноса строки. Строка "Иван Петров" прочитается как два отдельных значения. Для чтения целой строки используй `bufio.Scanner`.

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])
        }
    }
}

Зарегистрируйтесь бесплатно, чтобы пройти квиз, решить задание с автопроверкой и вести прогресс.