go要求包名与目录名严格一致且大小写敏感,目录utils下必须声明package utils;跨包导入须用模块路径而非相对路径;导出标识符首字母需大写;循环导入需通过接口解耦或下沉逻辑解决。

包名与目录名必须严格一致
GoLand 里新建一个 utils 目录,里面放工具函数,但如果你在 utils/string.go 文件顶部写 package helper,编译会直接报错:package helper is not in GOROOT 或更常见的 import "xxx/utils" is a program, not an importable package。Go 要求:一个目录下的所有 .go 文件,package 声明必须和目录名完全相同(大小写敏感),且不能是 main。
- 正确做法:目录名
utils→ 文件首行package utils - 错误示例:
mkdir utils && echo "package helper" > utils/str.go→ 后续import "./utils"失败 - 别用
common、base这类模糊名称;优先用语义明确的包名,比如auth、cache、httpclient
跨包调用时路径要从模块根目录算起
你在 cmd/api/main.go 里想用 internal/service/user.go 里的函数,不能写 import "../internal/service" —— Go 模块系统不认相对路径。必须用模块定义的导入路径,也就是 go.mod 里 module 行声明的那个名字。
GoLand 2026.1.1 是 2026.1 发布后的首个维护修正版本,适合已经开始体验 2026.1 新功能并希望同步补丁的开发者。它更适合用于入门项目、现有项目迁移测试和 IDE 行为验证。
- 假设
go.mod是module github.com/yourname/project,那就要写import "github.com/yourname/project/internal/service" -
internal/目录下的包只能被同模块内代码导入,外部模块无法引用,这是 Go 的封装机制,不是 bug - 如果项目没初始化模块(没
go mod init),import会退化为本地路径导入(如./utils),但这种写法无法发布、无法被他人go get,仅限本地原型验证
导出函数/结构体必须首字母大写
你在 utils/sanitize.go 里写了 func cleanInput(s string) string,然后在 main.go 中尝试调用 utils.cleanInput("xss"),编译器会报错:cannot refer to unexported name utils.cleanInput。Go 没有 public/private 关键字,靠命名约定控制可见性。
- 首字母小写(
cleanInput)→ 仅包内可见 - 首字母大写(
CleanInput)→ 可被其他包通过utils.CleanInput()调用 - 结构体字段也一样:
type User struct { Name string; age int }中Name可导出,age不可 - 别为了“方便”把所有东西都大写;只暴露真正需要被复用的接口,内部实现保持小写
避免循环导入:用接口解耦依赖
当 service 包需要调用 db 包的 SaveUser(),而 db 包又反过来依赖 service 里的某个校验逻辑时,go build 会直接失败:import cycle not allowed。这不是 GoLand 的限制,是 Go 编译器强制的。
- 典型场景:
db/user.go里调用了service.ValidateUser()→ 循环 - 解法:在
service包里定义接口,比如type Validator interface { Validate(*User) error },然后让db只依赖这个接口,不依赖具体实现 - 或者把校验逻辑下沉到
model或utils包,让db和service都只导入它,不互相导入 - GoLand 的 “Find Usages”(Alt+F7)能快速帮你发现潜在循环,但最终得靠设计提前规避
internal/ 目录的语义约束和接口解耦的时机——等真出现循环导入再重构,往往要动十几处调用点。不如一开始就把“谁该依赖谁”画个草图。










