← Назад к вопросам

Что произойдёт если присвоить какой-нибудь символ элементу строки?

2.0 Middle🔥 181 комментариев
#Основы Go

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ошибка компиляции: строки в Go неизменяемы

Если вы попытаетесь присвоить символ (байт или руну) элементу строки по индексу в Go, компилятор выдаст ошибку. Это происходит потому, что строки в Go являются неизменяемыми (immutable) последовательностями байт.

Пример ошибочного кода

package main

func main() {
    str := "Hello"
    str[0] = 'h'  // ОШИБКА: невозможно присвоить str[0]
}

При попытке скомпилировать этот код вы получите ошибку:

cannot assign to str[0]

Почему строки неизменяемы?

  1. Безопасность и предсказуемость — неизменяемость предотвращает случайное изменение строк, которые могут использоваться в нескольких местах.
  2. Потокобезопасность — строки можно безопасно использовать в конкурентных программах без блокировок.
  3. Эффективность — строки могут копироваться по ссылке без глубокого копирования.
  4. Хешируемость — неизменяемость позволяет использовать строки как ключи в map.

Как правильно работать со строками в Go

1. Создание новой строки с изменениями

package main

import (
    "fmt"
    "strings"
)

func main() {
    original := "Hello"
    
    // Способ 1: через преобразование в слайс рун
    runes := []rune(original)
    runes[0] = 'h'
    modified1 := string(runes)
    fmt.Println(modified1) // "hello"
    
    // Способ 2: с помощью функций пакета strings
    modified2 := strings.Replace(original, "H", "h", 1)
    fmt.Println(modified2) // "hello"
    
    // Способ 3: конкатенация
    modified3 := "h" + original[1:]
    fmt.Println(modified3) // "hello"
}

2. Обработка многобайтовых символов (UTF-8)

Важно помнить, что Go использует кодировку UTF-8, где символы могут занимать от 1 до 4 байт:

package main

import "fmt"

func main() {
    str := "Привет"  // Кириллица - многобайтовые символы
    
    // НЕПРАВИЛЬНО: работа с байтами может испортить символы
    // bytes := []byte(str)
    // bytes[0] = 'X'  // Может сломать UTF-8 последовательность
    
    // ПРАВИЛЬНО: преобразование в слайс рун
    runes := []rune(str)
    if len(runes) > 0 {
        runes[0] = 'Х'  // Заменяем первую букву
    }
    result := string(runes)
    fmt.Println(result) // "Хривет"
}

3. Производительность преобразований

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

package main

import (
    "fmt"
    "strings"
    "time"
)

func main() {
    largeStr := strings.Repeat("Hello ", 10000)
    
    start := time.Now()
    
    // Медленно: создаёт копию всех данных
    runes := []rune(largeStr)
    if len(runes) > 0 {
        runes[0] = 'h'
    }
    _ = string(runes)
    
    fmt.Printf("Через []rune: %v\n", time.Since(start))
    
    start = time.Now()
    
    // Быстрее: использует Builder
    var builder strings.Builder
    builder.WriteString("h")
    builder.WriteString(largeStr[1:])
    _ = builder.String()
    
    fmt.Printf("Через Builder: %v\n", time.Since(start))
}

Ключевые выводы

  1. Строки в Go неизменяемы — прямое изменение элементов невозможно.
  2. Для модификации строк необходимо создавать новые строки на основе существующих.
  3. Используйте []rune для работы с Unicode-символами, особенно когда важна правильная обработка многобайтовых символов.
  4. Для производительности при частых модификациях больших строк используйте strings.Builder или []byte с последующим преобразованием в строку.
  5. Помните о UTF-8 — индексация по байтам (через str[i]) возвращает байты, а не символы, что может привести к ошибкам с не-ASCII строками.

Неизменяемость строк — это фундаментальное свойство языка Go, которое обеспечивает безопасность, производительность и простоту работы с конкурентным кодом. Все стандартные библиотеки и идиоматичный код Go построены с учётом этого свойства.