Go run
Go 的 `go run` 命令常被拿来说明,简洁的工具链如何让编译型语言几乎像脚本语言一样使用,尤其是像 `go run .` 这样的约定,以及自动依赖获取。评论者将其与 JavaScript/TypeScript 生态对比,后者多种运行时、模块系统和包管理器会让基本任务显得更复杂,不过 Deno 和 Bun 等新工具正在缩小这一差距。这场讨论凸显了语言设计、错误处理、构建系统和依赖管理中,简洁性与灵活性之间的更大权衡。
go run 的用法与约定
- 许多人指出,一旦
main拆分到多个文件中,go run main.go就会失效;go run .会运行当前包,并且可以处理多个文件和子目录(go run ./cmd/foo)。 - 也有不少人抱怨教程强调
go run file.go,而不是更简单、也更具可扩展性的go run .。 - 有些人希望不带参数的
go run能像其他go子命令一样自动检测main包,但也有人认为在有多个cmd/*二进制时会产生歧义。 - 模块带来了一些阻力:你通常必须位于模块根目录才能
go run .,或者使用-C来切换目录。
简洁性、约定与学习曲线
- Go 因其可预测的布局而受到称赞:目录即包,
cmd/用于二进制;浏览陌生代码库时往往很直观。 - 但也有人觉得“简单 vs 复杂”的边界并不直观(例如需要知道何时使用
go run .,何时使用go run path/to/main.go)。 - 对于教程和心智模型究竟应该在多大程度上受先前语言经验影响,存在争论。
与 JS/TS 及其他生态的比较
- 有人将
go run与 Node/TypeScript 生态做对比,指出其碎片化(npm、yarn、pnpm;CommonJS vs ESM;TS 转译、Jest/Babel 配置)。 - 也有人反驳说,Node 已经可以运行 ESM(
.mjs),也可以通过简单工具链运行 TS(tsc、loader),而且更新的工具(Deno、Bun、tsx、npx)也让 TS 脚本同样容易。 - 还提到了 Rust 的
cargo run、Python 工具(Poetry)、Nix 和 Bazel,作为类似的“构建 + 运行”流程。
依赖获取与安全性
- 一个被强调的特性是:
go run会自动从模块路径下载依赖。 - 支持者喜欢这种低摩擦的工作流,认为版本由
go.mod/go.sum锁定,并由 Go 代理支撑。 - 批评者认为,在
run过程中自动获取依赖是安全/运维上的反模式,更倾向于明确的“先获取,再运行”步骤,尤其是在首次下载时。
对 Go 的更广泛看法
- 许多人称赞 Go 的工具链(单一工具链、静态二进制、交叉编译、简单部署;有时甚至不需要 Docker)。
- 也有人批评 Go 的错误处理过于冗长,以及与 Rust 或 TypeScript 相比缺少高级类型特性,不过也有人欣赏其显式性。
- Go 被看作介于底层的 Rust 和高层的 TS 之间,很适合后端服务和小型实用工具,但并不一定能满足所有人的语言偏好。