Что такое экспортируемые и неэкспортируемые идентификаторы в Go?

Ответ

В Go управление видимостью (инкапсуляция) реализовано на уровне пакетов и определяется регистром первой буквы идентификатора (имени переменной, константы, типа, функции, поля структуры и т.д.).

  • Экспортируемый (публичный) идентификатор начинается с заглавной буквы. Он доступен из любого другого пакета, который импортирует пакет, где он определен.
  • Неэкспортируемый (приватный) идентификатор начинается со строчной буквы. Он доступен только внутри того же пакета, в котором определен.

Пример

Допустим, у нас есть пакет calculator:

// file: calculator/calculator.go
package calculator

// pi - неэкспортируемая константа, доступна только внутри пакета calculator
const pi = 3.14159

// Add - экспортируемая функция, доступна из других пакетов
func Add(a, b int) int {
    return a + b
}

// subtract - неэкспортируемая функция
func subtract(a, b int) int {
    return a - b
}

Теперь используем его из пакета main:

// file: main.go
package main

import (
    "fmt"
    "myproject/calculator"
)

func main() {
    // Корректный вызов экспортируемой функции
    sum := calculator.Add(5, 3)
    fmt.Println("Sum:", sum) // Output: Sum: 8

    // Ошибка компиляции: попытка доступа к неэкспортируемому идентификатору
    // diff := calculator.subtract(5, 3) // cannot refer to unexported name calculator.subtract
    // fmt.Println(calculator.pi)       // cannot refer to unexported name calculator.pi
}

Ключевые моменты

  1. Область видимости — пакет: В Go нет модификаторов public, private или protected, как в других языках. Видимость определяется исключительно на уровне пакетов.
  2. Применяется ко всему: Это правило касается переменных, констант, функций, типов (структур, интерфейсов) и их полей/методов.
  3. Инкапсуляция: Это основной механизм инкапсуляции в Go, позволяющий скрыть детали реализации пакета и предоставить наружу только стабильный и продуманный API.