Изменение глобальной переменной

К каким негативным последствиям может привести данный фрагмент кода, и как это исправить? Приведите корректный пример реализации.

var justString string

func someFunc() {
    v := createHugeString(1 << 10)
    justString = v[:100] 
}

func main() { 
    someFunc()
}

Это учебное задание, не могу понять конкретную проблему. 1) Изменение глобальной переменной в функции может быть неожиданным? 2) Переменная созданная на стеке и потом положенная в глобальную переменную приведет к каким-то ошибкам? Предполагаю, что корректная реализация выглядит вот так:

func someFunc() {
    justString = createHugeString(100)
}

или

func someFunc() {
    justString = createHugeString(1 << 10)[:100]
}

Но почему так могло бы быть лучше не знаю.


Ответы (1 шт):

Автор решения: Nikolay Tuzov

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

Такую строку можно, например, записывать в файл и читать по мере необходимости:

func someFunc() {
    f, err := os.Create("huge_string.txt")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    _, err = createHugeString(1 << 30, f) // Передаем файл в качестве io.Writer, чтобы записать строку в него
}

Ещё один момент - строки в Go иммутабельны, то есть когда мы их изменяем, фактически создаём новую строку. Поэтому, если мы хотим изменить строку, то лучше использовать []byte:

func someFunc() {
    b := []byte(createHugeString(1 << 30))
    b = b[:100]
}

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

  1. К глобальным переменным можно обращаться из любой функции, поэтому их изменение может быть неожиданным. Такое поведение может привести к ошибкам, которые очень сложно отлаживать. На самом деле, глобальные переменные допустимы, но их использование должно быть оправдано. Например, в некоторых случаях они могут быть полезны для конфигурации приложения, но в большинстве случаев лучше использовать локальные переменные.

  2. Локальные переменные создаются на стеке, а глобальные - на куче. Работа со стеком быстрее, чем с кучей, поэтому лучше использовать локальные переменные, если это возможно.

Приведенная вами "корректная реализация" не совсем корректна. Вы просто избавились от промежуточной переменной v, но проблема была не в ней. Избавляться нужно было от глобальной переменной justString. И в таком случае результат работы функции нужно вернуть, иначе он просто потеряется после завершения работы функции someFunc():

func someFunc() string {
    return createHugeString(1 << 10)[:100]
}
→ Ссылка