Как реализовано сокрытие данных (инкапсуляция) в Go?

Ответ

В Go нет классических модификаторов доступа (таких как private, public, protected в других языках), но сокрытие данных (инкапсуляция) реализуется через простые правила именования на уровне пакетов:

  1. Экспортируемые (публичные) идентификаторы: Идентификаторы (переменные, функции, типы, методы), начинающиеся с заглавной буквы, являются экспортируемыми. Это означает, что они доступны для использования из других пакетов.
  2. Неэкспортируемые (приватные) идентификаторы: Идентификаторы, начинающиеся с прописной буквы, не экспортируются. Они доступны только внутри того пакета, в котором они объявлены.

Это называется инкапсуляцией на уровне пакета.

Пример:

package bank // Пакет bank

import "fmt"

// Account - публичный тип (начинается с заглавной буквы).
// Его поля owner и balance являются приватными.
type Account struct {
    owner   string // приватное поле (не экспортируется)
    balance int    // приватное поле (не экспортируется)
}

// NewAccount - публичная функция-конструктор для создания нового Account.
// Это предпочтительный способ создания экземпляров, так как он позволяет
// контролировать инициализацию приватных полей.
func NewAccount(owner string, initialBalance int) *Account {
    if !validateAmount(initialBalance) {
        fmt.Println("Начальный баланс должен быть положительным.")
        return nil
    }
    return &Account{owner: owner, balance: initialBalance}
}

// Deposit - публичный метод для внесения средств.
func (a *Account) Deposit(amount int) {
    if validateAmount(amount) {
        a.balance += amount
        fmt.Printf("Внесено %d. Новый баланс: %dn", amount, a.balance)
    } else {
        fmt.Println("Сумма для внесения должна быть положительной.")
    }
}

// Balance - публичный метод для получения текущего баланса.
func (a *Account) Balance() int {
    return a.balance
}

// validateAmount - приватная функция (начинается с прописной буквы).
// Доступна только внутри пакета bank.
func validateAmount(amount int) bool {
    return amount > 0
}

Использование из другого пакета (например, main):

package main

import (
    "fmt"
    "your_module/bank" // Предполагается, что пакет bank находится в your_module
)

func main() {
    // Создаем новый аккаунт через публичный конструктор
    myAccount := bank.NewAccount("Alice", 100)
    if myAccount == nil {
        return
    }

    // Доступ к публичному методу Deposit
    myAccount.Deposit(50)

    // Доступ к публичному методу Balance
    fmt.Printf("Текущий баланс: %dn", myAccount.Balance())

    // Попытка прямого доступа к приватным полям вызовет ошибку компиляции:
    // fmt.Println(myAccount.balance) // Ошибка: myAccount.balance не экспортируется
    // bank.validateAmount(10)        // Ошибка: bank.validateAmount не экспортируется
}

Таким образом, приватные поля и функции доступны только внутри своего пакета, а взаимодействие с ними извне возможно только через публичные методы и функции, что обеспечивает контроль над состоянием объектов и соблюдение принципов инкапсуляции.