Как в Go реализуется инкапсуляция?

Ответ

В Go нет ключевых слов public, private или protected, как в других языках. Инкапсуляция и управление видимостью реализуются на уровне пакетов с помощью простого правила:

Имя, начинающееся с заглавной буквы, является экспортируемым (публичным). Имя, начинающееся со строчной буквы, — неэкспортируемым (приватным для пакета).

Существует два основных способа скрыть детали реализации:

  1. Неэкспортируемые идентификаторы (уровень пакета)

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

    // В пакете 'counter'
    
    // secretCounter не виден за пределами пакета 'counter'
    var secretCounter int 
    
    // Increment является экспортируемой функцией
    func Increment() {
        secretCounter++
    }
  2. Использование интерфейсов для сокрытия реализации

    Этот подход позволяет полностью скрыть конкретную структуру, предоставляя наружу только интерфейс. Пользователь пакета работает с поведением (методами интерфейса), а не с конкретными данными.

    // В пакете 'database'
    
    // DB - публичный интерфейс
    type DB interface {
        Query(string) (string, error)
    }
    
    // pgDB - неэкспортируемая структура, конкретная реализация
    type pgDB struct {
        connection string
        // ... другие приватные поля
    }
    
    func (db *pgDB) Query(q string) (string, error) {
        // ... логика запроса к PostgreSQL
        return "result", nil
    }
    
    // New - публичная "фабрика", возвращает публичный интерфейс,
    // скрывая приватную реализацию.
    func New(connStr string) DB {
        return &pgDB{connection: connStr}
    }

    В этом примере код из другого пакета может создать объект pgDB через database.New(), но получит его в виде переменной типа database.DB. Он не будет иметь доступа к полям структуры pgDB и сможет вызывать только методы, определенные в интерфейсе DB.