Menu
Coddy logo textTech

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

Часть раздела Логика и управление потоком путешествия по GO на Coddy — урок 52 из 68.

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

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

// Эти элементы экспортируемые (публичные)
var Name string
func Calculate() int
type Person struct

Неэкспортируемые идентификаторы начинаются со строчной буквы и доступны только внутри того же пакета. Они являются «приватными» для вашего пакета.

// Это неэкспортируемые (приватные)
var age int
func helper() string
type config struct

Это соглашение об именовании — это способ Go управлять доступом без необходимости использования таких ключевых слов, как public или private. Когда вы пытаетесь использовать неэкспортируемый идентификатор из другого пакета, Go выдаст ошибку компиляции, поскольку этот идентификатор не виден за пределами своего пакета.

quiz iconПроверьте себя

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

quiz iconПроверьте себя

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

quiz iconПроверьте себя

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

challenge icon

Задание

Легко

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

Вы получите два входных значения:

  • Строка, содержащая определения пакетов в формате "package_name:identifier1:type1:visibility1,identifier2:type2:visibility2|package_name:identifier1:type1:visibility1" (например, "utils:helper:function:private,Calculate:function:public|main:name:variable:private,Version:variable:public")
  • Строка, содержащая попытки доступа в формате "accessing_package.identifier1,accessing_package.identifier2,accessing_package.identifier3" (например, "main.helper,main.Calculate,utils.Version")

Ваша задача:

  1. Разобрать первый входной параметр, разделив его по символу вертикальной черты, чтобы получить определения отдельных пакетов.
  2. Для каждого определения пакета разделить его по двоеточиям, чтобы получить имя пакета и его идентификаторы.
  3. Для каждого определения идентификатора разделить его по двоеточиям, чтобы получить имя идентификатора, тип и предполагаемую видимость.
  4. Создать функцию с именем fixIdentifierName, которая принимает имя идентификатора и предполагаемую видимость и возвращает исправленное имя:
    • Если видимость — "public", убедитесь, что идентификатор начинается с заглавной буквы.
    • Если видимость — "private", убедитесь, что идентификатор начинается со строчной буквы.
  5. Вывести заголовок анализа пакетов: "=== PACKAGE VISIBILITY ANALYSIS ==="
  6. Для каждого пакета вывести информацию о пакете:
    • "Package: [package_name]"
    • Для каждого идентификатора в пакете:
      • Если имя идентификатора требует исправления: "- [original_name] ([type]) -> [corrected_name] (visibility: [visibility])"
      • Если имя идентификатора правильное: "- [identifier_name] ([type]) (visibility: [visibility]) ✓"
  7. Разобрать второй входной параметр, разделив его по запятым, чтобы получить отдельные попытки доступа.
  8. Для каждой попытки доступа разделить её по точкам, чтобы получить обращающийся пакет и идентификатор, к которому осуществляется доступ.
  9. Вывести заголовок проверки доступа: "=== ACCESS VALIDATION ==="
  10. Для каждой попытки доступа определить, является ли доступ допустимым:
    • Найти пакет, содержащий этот идентификатор.
    • Проверить, начинается ли исправленное имя идентификатора с заглавной буквы (экспортируемый).
    • Если идентификатор экспортируемый: "[accessing_package] accessing [target_package].[corrected_identifier_name]: ✓ ALLOWED (exported)"
    • Если идентификатор неэкспортируемый: "[accessing_package] accessing [target_package].[corrected_identifier_name]: ✗ DENIED (unexported)"
    • Если идентификатор не существует: "[accessing_package] accessing [target_package].[identifier_name]: ✗ NOT FOUND"
  11. Подсчитать и вывести итоговую статистику:
    • "=== SUMMARY ==="
    • "Total packages analyzed: [number_of_packages]"
    • "Total identifiers processed: [total_number_of_identifiers]"
    • "Identifiers requiring fixes: [number_of_identifiers_that_needed_fixing]"
    • "Access attempts: [number_of_access_attempts]"
    • "Allowed accesses: [number_of_allowed_accesses]"
    • "Denied accesses: [number_of_denied_accesses]"
  12. Вывести финальные рекомендации:
    • Если были идентификаторы, требующие исправления: "Recommendation: Fix identifier naming to follow Go conventions"
    • Если все идентификаторы были правильными: "All identifiers follow proper Go naming conventions"

Используйте пакет strings для разделения входных строк, пакет fmt для форматированного вывода и функции манипуляции строками для проверки и изменения имен идентификаторов. Эта задача демонстрирует, как соглашение об именовании в Go управляет видимостью пакетов, и помогает понять разницу между экспортируемыми и неэкспортируемыми идентификаторами.

Шпаргалка

Go управляет видимостью через соглашения об именовании без явных ключевых слов, таких как public или private.

Экспортируемые идентификаторы начинаются с заглавной буквы и доступны из других пакетов:

// Эти идентификаторы экспортируемые (публичные)
var Name string
func Calculate() int
type Person struct

Неэкспортируемые идентификаторы начинаются со строчной буквы и доступны только внутри того же пакета:

// Эти идентификаторы неэкспортируемые (приватные)
var age int
func helper() string
type config struct

Попытка доступа к неэкспортируемым идентификаторам из других пакетов приводит к ошибкам компиляции.

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

package main

import (
	"fmt"
	"strings"
)

func main() {
	// Чтение входных данных
	var packageDefinitions string
	var accessAttempts string
	fmt.Scanln(&packageDefinitions)
	fmt.Scanln(&accessAttempts)

	// TODO: Напишите свой код ниже
	
	// Создайте функцию fixIdentifierName
	
	// Разбор определений пакетов
	
	// Отображение анализа пакетов
	
	// Разбор попыток доступа
	
	// Отображение проверки доступа
	
	// Расчет и отображение сводной статистики
	
	// Отображение рекомендаций
}
quiz iconПроверьте себя

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

Все уроки раздела Логика и управление потоком