Menu
CoddyTech

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

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

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

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

// Они экспортируются (public)
var Name string
func Calculate() int
type Person struct

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

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

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

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]) ✓"
    • Разобрать второй вход, разделив его по запятым, чтобы получить отдельные попытки доступа
    • Для каждой попытки доступа разделить её по точкам, чтобы получить пакет, из которого выполняется обращение, и идентификатор, к которому обращаются
    • Вывести заголовок проверки доступа: "=== ACCESS VALIDATION ==="
    • Для каждой попытки доступа определить, допустимо ли обращение:
      • Найти пакет, содержащий идентификатор
      • Проверить, начинается ли исправленное имя идентификатора с заглавной буквы (экспортируется ли он)
      • Если идентификатор экспортируется: "[accessing_package] accessing [target_package].[corrected_identifier_name]: ✓ ALLOWED (exported)"
      • Если идентификатор не экспортируется: "[accessing_package] accessing [target_package].[corrected_identifier_name]: ✗ DENIED (unexported)"
      • Если идентификатор не существует: "[accessing_package] accessing unknown.[identifier_name]: ✗ NOT FOUND" (вывести слово unknown в качестве имени пакета; эта попытка учитывается как запрещённый доступ)
    • Подсчитать и вывести сводную статистику:
      • "=== 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]"
    • Вывести итоговые рекомендации:
      • Если нашлись идентификаторы, требующие исправления: "Recommendation: Fix identifier naming to follow Go conventions"
      • Если все идентификаторы указаны правильно: "All identifiers follow proper Go naming conventions"

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

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

package main

import (
	"fmt"
	"strings"
)

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

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

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

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

Потренируйтесь самостоятельно: Онлайн-компилятор Go