Menu
Coddy logo textTech

Экспортируемые и неэкспортируемые поля

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 47 из 107.

В Go инкапсуляция на уровне struct контролируется регистром имен полей. Это простое правило определяет, можно ли получить доступ к полям извне пакета, в котором определена struct.

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

// В пакете "user"
type User struct {
    Name     string  // Экспортируемое - доступно везде
    Email    string  // Экспортируемое - доступно везде
    password string  // Неэкспортируемое - доступно только в пакете "user"
    age      int     // Неэкспортируемое - доступно только в пакете "user"
}

Когда другой пакет импортирует и использует эту структуру, он может взаимодействовать только с экспортируемыми полями:

// В пакете "main"
import "user"

func main() {
    u := user.User{
        Name:  "Alice",      // работает
        Email: "a@mail.com", // работает
        // password: "secret", // ошибка компиляции: неизвестное поле
    }
    
    fmt.Println(u.Name)     // работает
    // fmt.Println(u.password) // ошибка компиляции: нельзя ссылаться на неэкспортируемое поле
}

Этот механизм защищает конфиденциальные данные и детали внутренней реализации. Поле password нельзя прочитать или изменить напрямую извне пакета, что заставляет другой код использовать предоставляемые вами методы. Это подход Go к реализации сокрытия данных — основного принципа инкапсуляции в объектно-ориентированном программировании.

challenge icon

Задание

Легко

Давайте создадим систему банковских счетов, которая демонстрирует инкапсуляцию через экспортируемые и неэкспортируемые поля. Вы создадите пакет, который защищает конфиденциальные финансовые данные, предоставляя при этом безопасную публичную информацию.

Вы организуете свой код в двух файлах:

  • account.go: Создайте структуру BankAccount в пакете main, которая моделирует реальный банковский счет с надлежащей защитой данных:
    • HolderName (экспортируемое) — имя владельца счета, которое можно безопасно отображать публично
    • AccountType (экспортируемое) — тип счета (например, "Savings", "Checking")
    • balance (неэкспортируемое) — фактический баланс, который должен быть защищен
    • pin (неэкспортируемое) — PIN-код счета, строго конфиденциальные данные
    Добавьте функцию-конструктор NewBankAccount, которая принимает имя владельца, тип счета, начальный баланс и PIN-код, а затем возвращает указатель на новый BankAccount. Также добавьте метод GetPublicInfo() string, который возвращает строку в формате: Account: [HolderName] ([AccountType])
  • main.go: Считайте данные счета из входных данных, создайте BankAccount с помощью конструктора и продемонстрируйте инкапсуляцию. Выведите публичную информацию с помощью метода, а затем напрямую обратитесь к каждому экспортируемому полю и выведите их на отдельных строках. Неэкспортируемые поля (balance и pin) защищены — вы можете установить их только через конструктор.

Будут предоставлены следующие входные данные:

  • Строка 1: Имя владельца счета
  • Строка 2: Тип счета
  • Строка 3: Начальный баланс (в виде числа с плавающей точкой)
  • Строка 4: PIN-код

Например, для входных данных Alice Johnson, Savings, 5000.50 и 1234 ваш вывод должен быть следующим:

Account: Alice Johnson (Savings)
Holder: Alice Johnson
Type: Savings

Обратите внимание, что баланс и PIN-код никогда не появляются в выводе — они надежно скрыты внутри структуры и доступны только внутри пакета. Это и есть инкапсуляция в действии: конфиденциальные данные защищены, в то время как публичная информация остается доступной.

Шпаргалка

В Go **инкапсуляция** управляется регистром имен полей в структурах:

  • **Заглавные** поля являются *экспортируемыми* (доступны из любого пакета)
  • **Строчные** поля являются *неэкспортируемыми* (доступны только внутри того же пакета)
type User struct {
    Name     string  // Экспортируемое — доступно везде
    Email    string  // Экспортируемое — доступно везде
    password string  // Неэкспортируемое — доступно только в том же пакете
    age      int     // Неэкспортируемое — доступно только в том же пакете
}

При использовании структуры из другого пакета доступны только экспортируемые поля:

import "user"

func main() {
    u := user.User{
        Name:  "Alice",      // работает
        Email: "a@mail.com", // работает
        // password: "secret", // ошибка компиляции: неизвестное поле
    }
    
    fmt.Println(u.Name)     // работает
    // fmt.Println(u.password) // ошибка компиляции: нельзя ссылаться на неэкспортируемое поле
}

Этот механизм защищает конфиденциальные данные и детали внутренней реализации, заставляя внешний код использовать предоставленные методы для доступа.

Попробуйте сами

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Считать имя владельца счета
	holderName, _ := reader.ReadString('\n')
	holderName = strings.TrimSpace(holderName)

	// Считать тип счета
	accountType, _ := reader.ReadString('\n')
	accountType = strings.TrimSpace(accountType)

	// Считать начальный баланс
	balanceStr, _ := reader.ReadString('\n')
	balanceStr = strings.TrimSpace(balanceStr)
	balance, _ := strconv.ParseFloat(balanceStr, 64)

	// Считать PIN
	pinStr, _ := reader.ReadString('\n')
	pin := strings.TrimSpace(pinStr)

	// TODO: Создать новый BankAccount, используя конструктор
	// account := NewBankAccount(...)

	// TODO: Вывести публичную информацию, используя метод GetPublicInfo()

	// TODO: Вывести имя владельца, обратившись напрямую к экспортируемому полю
	// fmt.Println("Holder:", ...)

	// TODO: Вывести тип счета, обратившись напрямую к экспортируемому полю
	// fmt.Println("Type:", ...)

	// Note: balance и pin не экспортированы — к ним нельзя обратиться напрямую отсюда
	// Они безопасно инкапсулированы внутри структуры

	_ = balance // Удалите эту строку, когда будете использовать balance
	_ = pin     // Удалите эту строку, когда будете использовать pin
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование