#13.3 golang Видимость имён - что видно снаружи пакета: правило заглавной буквы (экспортируемые и неэкспортируемые имена)

Правило одной буквы

В golang видимость имени за пределами пакета определяется первой буквой имени — переменной, константы, функции или типа:

  • имя начинается с заглавной буквы — оно экспортируемое (exported), то есть видно снаружи пакета и доступно после импорта;
  • имя начинается со строчной — оно неэкспортируемое (unexported), то есть доступно только внутри своего пакета.

Это аналог public/private из других языков, только вместо ключевых слов — регистр первой буквы. Фактически мы пользовались этим с самого первого запуска минимальной программы: fmt.Println() — вызов экспортируемой функции Println из пакета fmt.

Пример

Пусть пакет utils нашего модуля объявляет две функции и константу — файл utils/strings.go:

package utils

const Version = "1.0" // экспортируемая константа

// Greeting - экспортируемая функция: заглавная буква,
// её можно вызывать из других пакетов
func Greeting(name string) string {
	return greetingWord() + ", " + name + "!"
}

// greetingWord - неэкспортируемая: строчная буква,
// доступна только внутри пакета utils
func greetingWord() string {
	return "Привет"
}

Тогда в main.go (пакет main):

package main

import (
	"fmt"

	"myapp/utils"
)

func main() {
	fmt.Println(utils.Greeting("мир")) // работает
	fmt.Println(utils.Version)         // тоже работает

	fmt.Println(utils.greetingWord()) // ОШИБКА компиляции
}

для последней строки компилятор сообщит:

./main.go:15:14: undefined: utils.greetingWord

хотя функция существует — просто она не видна снаружи своего пакета (подробнее об объявлении функций).

Зачем так сделано

Экспортируемые имена образуют «интерфейс» пакета — то, ради чего его импортируют, а неэкспортируемые — внутреннюю реализацию, которую пакет может свободно менять, не ломая чужой код. Поэтому стараются экспортировать как можно меньше.

Что ещё важно знать

  • Внутри одного пакета все имена видны друг другу во всех его файлах — например, strings.go видит имена из calc.go того же пакета utils без всяких импортов.
  • Заглавной считается любая буква в верхнем регистре, не только латинская: имя Привет тоже будет экспортируемым (хотя так писать не принято).
  • Правило распространяется и на поля структур и их методы — эти темы идут дальше, см. список уроков.