导出与未导出
本课属于 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 会给出编译错误,因为该标识符在其所属包之外不可见。
挑战
简单通过修正导出和未导出标识符的命名规范,解决 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")
你的任务是:
- 通过按竖线拆分第一个输入,获取各个包定义
- 对于每个包定义,按冒号拆分,获取包名及其标识符
- 对于每个标识符定义,按冒号拆分,获取标识符名称、类型和预期可见性
- 创建一个名为
fixIdentifierName的函数,该函数接收标识符名称和预期可见性,并返回修正后的名称:- 如果可见性是
"public",确保标识符以大写字母开头 - 如果可见性是
"private",确保标识符以小写字母开头
- 如果可见性是
- 显示包分析标题:
"=== PACKAGE VISIBILITY ANALYSIS ===" - 对于每个包,显示包信息:
"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 函数
// 解析包定义
// 显示包分析结果
// 解析访问尝试
// 显示访问验证结果
// 计算并显示汇总统计信息
// 显示建议
}这节课包含一个小测验。开始学习即可作答,并记录你的进度。
逻辑与流程中的所有课
自己练习: Go 在线编译器