Ответ
Да, можно. Такой блок создает новую лексическую область видимости (lexical scope).
Основное правило: переменные, объявленные внутри этого блока, видны только в его пределах и "затеняют" (shadow) переменные с такими же именами из внешней области видимости.
func main() {
x := 10
fmt.Println("Внешний x:", x) // -> Внешний x: 10
{
y := 20
x := 99 // Эта переменная 'x' затеняет внешнюю. Она новая и локальная.
fmt.Println("Внутренний x:", x) // -> Внутренний x: 99
fmt.Println("Внутренний y:", y) // -> Внутренний y: 20
}
// fmt.Println(y) // Ошибка компиляции: y не определена в этой области видимости
fmt.Println("Снова внешний x:", x) // -> Снова внешний x: 10
}
Основные сценарии использования:
-
Ограничение "жизни" переменных: Полезно для временных переменных, которые нужны для небольшого участка логики и не должны "засорять" остальную часть функции. Это повышает читаемость и снижает риск ошибок.
-
Управление ресурсами с
defer
: Можно ограничить действиеdefer
локальным блоком, чтобы ресурс освободился сразу после использования, а не в конце всей функции.{ file, err := os.Open("temp.txt") if err != nil { /* ... */ } defer file.Close() // Сработает при выходе из этого блока {} // работа с файлом... } // Здесь файл уже закрыт.
-
Переиспользование имен переменных: Позволяет использовать короткие, стандартные имена (вроде
err
,n
,buf
) в разных, не связанных друг с другом логических блоках внутри одной большой функции.
Этот же механизм областей видимости используется в управляющих конструкциях, таких как if
, for
и switch
, когда переменная объявляется в их условии: if err := doSomething(); err != nil { ... }
.