Расскажите про области видимости (scope) в Go.

Ответ

Область видимости (scope) в Go — это регион исходного кода, в котором объявленный идентификатор (переменная, константа, тип, функция) является доступным. В Go используется лексическая область видимости, которая определяется структурой блоков {}.

Существует несколько уровней областей видимости, вложенных друг в друга:

  1. Всеобщая область видимости (Universe Scope)

    • Самый внешний уровень. Содержит все предопределенные идентификаторы из пакета builtin, такие как int, string, true, nil, len, make.
  2. Пакетная область видимости (Package Scope)

    • Идентификаторы, объявленные на верхнем уровне файла (вне любой функции). Они видны во всех файлах одного и того же пакета.
    • Если идентификатор начинается с заглавной буквы (например, MyVar), он экспортируется и доступен из других пакетов.
    • Если он начинается со строчной буквы (например, myVar), он виден только внутри своего пакета.
    // в файле a.go пакета mypkg
    var unexportedVar = 10 // видна только в пакете mypkg
    var ExportedVar = 20   // видна везде, где импортирован mypkg
  3. Блочная область видимости (Block Scope)

    • Наиболее локальный уровень. Идентификаторы, объявленные внутри блока {} (например, в теле функции, в операторах if, for, switch), видны только внутри этого блока.
    func someFunc() {
        x := 10 // видна только в someFunc
        if x > 5 {
            y := 20 // видна только внутри блока if
            fmt.Println(x, y) // OK
        }
        // fmt.Println(y) // Ошибка: y не определена здесь
    }

Перекрытие переменных (Variable Shadowing)

Go позволяет объявлять переменную с тем же именем во вложенной области видимости. Внутренняя переменная "затеняет" (shadows) внешнюю.

var x = "global"

func main() {
    fmt.Println(x) // Выведет: global

    x := "local" // Новая переменная x в области видимости main
    fmt.Println(x) // Выведет: local
}