Go 入门到精通-03-第一个程序Hello World

📅 2026/6/18 17:36:04
Go 入门到精通-03-第一个程序Hello World
基础入门 | Go 入门到精通 2026三第一个程序 Hello World 更新于 2026年6月 | ✍️ 原创文章转载请注明出处 | 作者布朗克168开篇编程界的传统学任何新语言第一个程序必须是Hello World。这不是形式主义——一个简单的 Hello World 背后藏着语言的程序结构、编译模型和运行机制。 本文目标写完 Hello World 后你能理解每一个关键字和每一行代码在做什么而不只是运行成功就行。1. 创建你的第一个 Go 程序步骤 1创建项目目录mkdir~/go-projects/hellocd~/go-projects/hello步骤 2初始化 Go Modulego mod init hello步骤 3创建 main.gotouchmain.go用你喜欢的编辑器打开main.go输入以下代码packagemainimportfmtfuncmain(){fmt.Println(Hello, World! )fmt.Println(欢迎来到 Go 语言的世界)}步骤 4运行$ go run main.go Hello, World! 欢迎来到 Go 语言的世界 恭喜你已经是一个 Go 程序员了至少是初级的。2. 完整程序结构逐行分析让我们把上面的 6 行代码拆开了揉碎了看packagemain要素说明packageGo 的关键字声明当前文件属于哪个包main特殊的包名告诉 Go 编译器这是一个可执行程序的入口位置必须是文件的第一行有效代码注释除外Go 中每个.go文件都必须属于一个包。包名是main时编译器会把它编译成一个可执行文件包名是其他名字如util、models时编译成库.a文件。importfmt要素说明import导入其他包的关键字fmtGo 标准库中的格式化 I/O 包类似 C 的stdio.hfmt是 Go 最常用的标准库之一提供了格式化输入输出功能fmt.Println()— 打印并换行fmt.Printf()— 格式化打印fmt.Scanln()— 读取输入fmt.Sprintf()— 格式化返回字符串如果需要导入多个包有两种写法// 写法一多行 import推荐import(fmtostime)// 写法二多个单行 import不推荐importfmtimportosimporttimefuncmain(){// ...}要素说明func声明函数的关键字main特殊函数名程序的唯一入口()参数列表此处无参数{函数体开始必须和 func 在同一行⚠️Go 的左大括号不能换行规则// ✅ 正确funcmain(){// ❌ 错误编译不通过funcmain(){这是 Go 编译器强制要求的目的是统一代码风格。fmt.Println(Hello, World! )这里做了两件事调用fmt包的Println函数注意Println首字母大写表示它是公开的/导出的传入一个字符串参数Hello, World! Go 的可见性规则极其简洁首字母大写 公开exported首字母小写 私有unexported。没有public/private/protected关键字。3. 三种运行方式go run vs go build vs go installGo 提供了三种运行代码的方式各有适用场景3.1 go run —— 快速运行go run main.go做了什么编译 运行但不保留编译产物适用场景开发调试、快速验证特点最方便但每次都要重新编译# 可以同时运行多个文件go run main.go helper.go# 运行整个包go run.3.2 go build —— 编译成二进制go build main.go# 生成 mainLinux/Mac或 main.exeWindows# 指定输出文件名go build-ohello main.go# 生成 hello 或 hello.exe做了什么只编译不运行生成可执行文件适用场景生产部署、发布特点一次编译到处运行同平台# 编译整个模块go build ./...# 编译并输出到指定目录go build-obin/hello.3.3 go install —— 编译并安装goinstall.# 编译并将二进制放到 $GOPATH/bin/ 下做了什么编译 安装到$GOPATH/bin适用场景安装 Go 工具如gopls、staticcheck特点编译产物放在统一位置方便全局调用三者的对比命令编译运行保留产物产物位置最佳场景go run✅✅❌临时目录开发调试go build✅❌✅当前目录生产部署go install✅❌✅$GOPATH/bin工具安装关于 go build 的更多选项# 查看编译详情go build-v.# 减小二进制体积去掉调试信息和符号表go build-ldflags-s -w-ohello.# 查看二进制大小ls-lhhello# -rwxr-xr-x 1 user staff 1.9M hello # 未压缩# -rwxr-xr-x 1 user staff 1.3M hello # 压缩后4. 编译产物深度分析让我们深入看看 Go 编译出来的二进制到底是个什么东西。查看文件信息# macOS/Linux$filehello hello: Mach-O64-bit executable arm64# Apple Silicon# 或hello: ELF64-bit LSB executable, x86-64# Linux# 查看大小$ls-lhhello -rwxr-xr-x1user staff1.9M hello# 查看依赖的动态库$ otool-Lhello# macOS$ ldd hello# Linux# Go 默认静态链接通常会输出 not a dynamic executable编译过程简析Go 的编译过程大体如下源代码 (.go) │ ▼ 词法分析 → Token 流 │ ▼ 语法分析 → AST抽象语法树 │ ▼ 类型检查 │ ▼ 中间代码生成SSA │ ▼ 优化 │ ▼ 机器码生成 │ ▼ 链接静态链接所有依赖 │ ▼ 可执行文件 关键差异Go 默认静态链接把运行时runtime、垃圾回收器、goroutine 调度器一起打包到二进制里。这就是为什么 Go 程序不需要目标机器安装 Go 环境就能运行。查看编译过程# 打印编译过程go build-x.# 查看生成的汇编代码go tool compile-Smain.go# 查看编译器优化决策go build-gcflags-m.# 输出中会看到逃逸分析等信息5. go fmt代码格式化Go 从诞生之初就内置了代码格式化工具目的很简单消灭代码风格之争。基本用法# 格式化单个文件gofmtmain.go# 格式化整个项目gofmt./...# 查看哪些文件需要格式化不实际修改gofmt-l.格式化什么把你的代码故意写成这样packagemainimportfmtfuncmain(){x:12fmt.Println(x)}运行go fmt后packagemainimportfmtfuncmain(){x:12fmt.Println(x)}自动修复了缩进Tab 缩进空格运算符两边加空格空行import 上下加空行goimports更智能的格式化goimports在gofmt的基础上还自动管理 import 语句# 安装goinstallgolang.org/x/tools/cmd/goimportslatest# 使用goimports-wmain.go# 自动添加缺失的 import移除未使用的 import VS Code 中设置go.formatTool: goimports后每次保存都会自动格式化 整理 import。6. 常见编译错误及排查初学 Go 时你大概率会遇到以下错误。别怕我都帮你整理好了错误 1package main is not in GOROOTpackage hello/main is not in GOROOT (/usr/local/go/src/hello/main)原因Go 在 GOPATH 或 GOROOT 中找不到你的包。解决# 确保在项目目录中初始化了 go.modcd~/go-projects/hello go mod init hello错误 2main.go:1:1: expected package, found import// ❌ 错误import 在 package 之前importfmtpackagemain解决package声明必须在所有非注释代码的第一行。// ✅ 正确packagemainimportfmt错误 3undefined: Printlnpackagemainfuncmain(){Println(Hello)// ❌ 缺少包名}解决调用其他包的公开函数时必须带上包名前缀fmt.Println(Hello)// ✅错误 4imported and not used: fmtpackagemainimportfmt// ❌ 导入了但没使用funcmain(){// 什么也没做}解决Go 不允许导入未使用的包——这在 Go 中是编译错误不是警告。# 删除多余的 import或者用空白标识符占位import_fmt// 仅执行 init 函数不直接使用错误 5syntax error: unexpected semicolon or newline before {funcmain()// ❌ 左大括号必须在同一行{解决Go 编译器会在行末自动插入分号所以左大括号不能换行。错误 6main redeclared in this blockfuncmain(){}// ❌ 同一包中只能有一个 main 函数funcmain(){}// ❌ 重复定义解决一个main包里只能有一个main函数。错误速查表错误信息关键词原因解决办法expected packagepackage 不在第一行把 package 声明移到第一行undefined未导入包或未声明检查 import 和变量声明imported and not used导入了但没使用删除或加_前缀declared and not used变量声明了但没使用删除或使用它cannot use类型不匹配检查类型可能需要显式转换missing return有返回值的函数缺少 return添加 return 语句7. go doc查阅文档Go 自带文档工具不需要联网就能查看标准库文档。基本用法# 查看包的文档go docfmt# 查看特定函数go doc fmt.Println# 查看特定类型的方法go doc net/http.ServeMux# 在浏览器中查看文档go doc-http:6060# 然后打开 http://localhost:6060在终端中快速查看# 查看 fmt.Printf 的格式化动词go doc fmt.Printf# 查看 strings 包有哪些函数go doc strings|head-20# 搜索文档Go 1.19go doc-allstrings|grep-ireplace写好自己的文档在 Go 中注释就是文档// Package calculator 提供基本的数学计算功能。packagecalculator// Add 返回两个整数的和。//// 示例://// sum : Add(1, 2)// fmt.Println(sum) // 3funcAdd(a,bint)int{returnab} 规范文档注释以被注释的标识符名称开头// Add ...。8. 跨平台交叉编译Go 的一大杀器一套代码编译到任何平台。基本用法GOOS目标操作系统和 GOARCH目标 CPU 架构的排列组合# 在 Mac 上编译 Linux 程序GOOSlinuxGOARCHamd64 go build-ohello-linux main.go# 在 Mac 上编译 Windows 程序GOOSwindowsGOARCHamd64 go build-ohello.exe main.go# 在 Linux 上编译 Mac 程序GOOSdarwinGOARCHarm64 go build-ohello-mac main.go# 编译 ARM Linux树莓派GOOSlinuxGOARCHarm64 go build-ohello-arm main.go支持的平台组合GOOSGOARCH说明linuxamd64Linux x86-64linuxarm64Linux ARM64树莓派4/5darwinamd64macOS Inteldarwinarm64macOS Apple Siliconwindowsamd64Windows x86-64windowsarm64Windows ARMlinuxriscv64RISC-V 架构查看完整列表go tool dist list禁用 CGO 的交叉编译如果你的代码不依赖 C 库建议禁用 CGO 以获得纯静态编译CGO_ENABLED0GOOSlinuxGOARCHamd64 go build-ohello-linux main.go交叉编译脚本把常用的编译命令写进 Makefile 或脚本# Makefile .PHONY: build-all build-all: GOOSlinux GOARCHamd64 go build -o bin/hello-linux-amd64 . GOOSlinux GOARCHarm64 go build -o bin/hello-linux-arm64 . GOOSdarwin GOARCHamd64 go build -o bin/hello-darwin-amd64 . GOOSdarwin GOARCHarm64 go build -o bin/hello-darwin-arm64 . GOOSwindows GOARCHamd64 go build -o bin/hello-windows.exe . echo ✅ 所有平台编译完成9. Hello World 变体多语言版既然学会了 Hello World来看看 Go 能玩出什么花样并发版 Hello Worldpackagemainimport(fmttime)funcmain(){messages:[]string{Hello, World! ,Hola, Mundo! ,Bonjour le Monde! ,Ciao Mondo! ,こんにちは世界! ,}for_,msg:rangemessages{gofunc(mstring){fmt.Println(m)}(msg)}// 等待 goroutine 执行完成time.Sleep(100*time.Millisecond)}HTTP 服务器版 Hello Worldpackagemainimport(fmtnet/http)funcmain(){http.HandleFunc(/,func(w http.ResponseWriter,r*http.Request){fmt.Fprintf(w,Hello, World! \n)fmt.Fprintf(w,你访问的路径是%s\n,r.URL.Path)})fmt.Println(服务器已启动http://localhost:8080)http.ListenAndServe(:8080,nil)}// 运行后打开浏览器访问 http://localhost:8080仅仅 15 行代码你就写出了一个 HTTP 服务器不需要 Tomcat、不需要 Nginx、不需要任何框架。这就是 Go 标准库的强大之处。小结与互动本文要点回顾Go 程序从package mainfunc main()开始package声明必须在第一行import导入依赖三种运行方式go run调试、go build编译、go install安装Go 编译为静态链接的单二进制文件运行不需要 Go 环境go fmt强制统一代码格式告别风格之争Go 不允许未使用的导入和变量——这是编译错误go doc离线查看文档交叉编译一套命令搞定多平台GOOSlinux GOARCHamd64 go build❓互动问题你的第一个 Hello World 跑起来了吗你觉得 Go 不允许未使用的变量/导入这个设计是好是坏试试改一下 Hello World打印一些中文或其他内容看看效果如何参考资料Go 官方入门教程Go 命令行文档Effective GoGo Build 模式下一篇[【Go 入门到精通 2026四变量与数据类型】]带你掌握 Go 的类型系统从此告别var tmp ???的困惑本文由布朗克168原创发布如需转载请联系作者并注明出处。