Avatar ·

Как преобразовать строку в число (int) в Go? Обработка ошибок и примеры

Всем привет! Я только начал изучать Go и столкнулся с проблемой преобразования строки в целое число. Пишу простой калькулятор, который принимает два числа из командной строки как строки и должен их сложить. Но я не могу понять, как правильно конвертировать строку в int. Вот мой код: ```go package main import ( "fmt" "os" ) func main() { if len(os.Args) != 3 { fmt.Println("Usage: calculator ") return } a := os.Args[1] b := os.Args[2] // Пытаюсь сложить, но получаю ошибку sum := a + b // Это конкатенация строк, а не сложение! fmt.Println("Sum:", sum) } ``` Я понимаю, что `a + b` просто склеивает строки, а не складывает числа. В других языках я использовал `int()` или `parseInt()`, но в Go это не работает напрямую. Я пробовал `int(a)`, но компилятор ругается: `cannot convert a (variable of type string) to type int`. Погуглил — нашел упоминание пакета `strconv`, но не до конца понял, как им пользоваться. Особенно меня смущает, что функция возвращает два значения. Как правильно обрабатывать ошибки, если пользователь введёт не число? И есть ли разница между `int` и `int64` в этом контексте? Буду благодарен за подробное объяснение с примерами! Хочется понять не только как сделать, но и почему именно так. <<>>

Использование пакета strconv для преобразования строки в число

В Go нет встроенного приведения типов между строкой и числом (как в Python или JavaScript). Для этой задачи существует стандартный пакет strconv (string conversion). Основная функция — strconv.Atoi() (ASCII to Integer), которая преобразует строку в int.

Базовый пример: strconv.Atoi()

package main

import (
    "fmt"
    "strconv"
)

func main() {
    str := "42"
    num, err := strconv.Atoi(str)
    if err != nil {
        fmt.Println("Ошибка преобразования:", err)
        return
    }
    fmt.Printf("Число: %d, тип: %T\n", num, num) // Число: 42, тип: int
}

Почему функция возвращает два значения?

В Go принято возвращать ошибку как второе значение. Если строка не является валидным числом (например, содержит буквы), err будет не nil, а num получит нулевое значение (0). Это заставляет разработчика явно обрабатывать ошибочные ситуации.

Исправленный калькулятор

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    if len(os.Args) != 3 {
        fmt.Println("Usage: calculator <num1> <num2>")
        return
    }

    a, err1 := strconv.Atoi(os.Args[1])
    b, err2 := strconv.Atoi(os.Args[2])

    if err1 != nil || err2 != nil {
        fmt.Println("Ошибка: оба аргумента должны быть целыми числами")
        return
    }

    sum := a + b
    fmt.Printf("Сумма: %d\n", sum)
}

Альтернативы: strconv.ParseInt() и strconv.ParseFloat()

Если вам нужно контролировать разрядность (int32, int64) или основание системы счисления (2, 8, 10, 16), используйте ParseInt():

// Преобразование строки в int64 с основанием 10
str := "255"
num64, err := strconv.ParseInt(str, 10, 64)
if err != nil {
    panic(err)
}
fmt.Printf("int64: %d\n", num64)

// Для чисел с плавающей точкой — ParseFloat()
floatStr := "3.14"
f, err := strconv.ParseFloat(floatStr, 64)
if err != nil {
    panic(err)
}
fmt.Printf("float64: %f\n", f)

Разница между int и int64

  • int — платформозависимый тип: 32 бита на 32-разрядных системах, 64 бита на 64-разрядных.
  • int64 — всегда 64 бита. Используйте его, если нужно гарантировать размер.
  • Atoi() возвращает int. Если вам нужен int64, используйте ParseInt(str, 10, 64).

Обработка ошибок: подробнее

Не игнорируйте ошибку через _ (подчёркивание) — это может привести к незаметным багам. Правильный паттерн:

num, err := strconv.Atoi(input)
if err != nil {
    // Логируем, выводим пользователю сообщение или используем значение по умолчанию
    fmt.Printf("Некорректный ввод '%s': %v\n", input, err)
    return
}
// Работаем с num

Проверка на пустую строку

Пустая строка также вызовет ошибку. Если вы ожидаете, что строка может быть пустой, проверяйте длину перед преобразованием:

if input == "" {
    // Обработка пустого значения
    num = 0
} else {
    num, err = strconv.Atoi(input)
}

Таким образом, strconv.Atoi() — самый простой и безопасный способ преобразовать строку в int в Go. Всегда обрабатывайте ошибку, и ваш код будет надёжным.

<<>>

Использование fmt.Sscanf() для парсинга чисел из строк

Иногда удобно использовать функцию fmt.Sscanf(), особенно если строка содержит несколько значений или имеет сложный формат. Она работает как scanf из C.

package main

import (
    "fmt"
)

func main() {
    str := "42 100 -5"
    var a, b, c int
    n, err := fmt.Sscanf(str, "%d %d %d", &a, &b, &c)
    if err != nil {
        fmt.Println("Ошибка парсинга:", err)
        return
    }
    fmt.Printf("Прочитано %d чисел: %d, %d, %d\n", n, a, b, c)
}

Плюсы и минусы

  • Плюсы: удобно для строк с разделителями (пробелы, запятые); можно парсить сразу несколько чисел.
  • Минусы: медленнее, чем strconv.Atoi(); сложнее обрабатывать ошибки для каждого отдельного числа.

Когда использовать

Если у вас одна строка с одним числом — используйте strconv.Atoi() или ParseInt(). Если строка содержит структурированные данные (например, "25 30 45"), fmt.Sscanf() может быть удобнее.

Также можно комбинировать: сначала разбить строку через strings.Split(), затем каждый элемент преобразовать через strconv.Atoi().

import "strings"

data := "10,20,30"
parts := strings.Split(data, ",")
for _, part := range parts {
    num, _ := strconv.Atoi(strings.TrimSpace(part))
    fmt.Println(num)
}

Выбирайте подход под вашу конкретную задачу.