Menu
CoddyTech

导出与未导出

本课属于 Coddy GO 学习旅程的“逻辑与流程”单元。第 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 会给出编译错误,因为该标识符在其所属包之外不可见。

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 在线编译器