Menu

Go Hello World:第一个 Go 程序逐行详解

逐行讲解 Go 语言的 hello world 程序:package main、import 块、func main 和 fmt.Println,以及如何运行它、新手最先遇到的编译错误。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

下面就是完整的程序。点击运行。

这几行一行都不能少。本页其余部分会解释每一行的作用。

逐行讲解

package main

每个 Go 文件都以 package 子句开头,写明它属于哪个包。main 这个名字很特殊:它把这个包标记为可执行程序。换成任何其他名字(package utils、package hello)都会得到一个库,其他代码可以导入它,但它本身不能运行。

import "fmt"

import 引入另一个包,让你可以使用它。fmt 是标准库中负责格式化和打印的包。导入之后,它导出的名字要通过包名来访问:fmt.Println、fmt.Printf、fmt.Sprintf。

要导入多个包,就用一个圆括号块,每行写一个路径:

import (
	"fmt"
	"strings"
)

如果一个文件导入了某个包却没有使用,Go 会拒绝编译。这让依赖列表始终如实,也是大多数人遇到的第一个错误。

func main()

func 用来声明函数。main 包里的 main 函数是程序的入口:main 开始时程序开始,main 返回时程序结束。它不接收参数,也不返回任何值。命令行参数来自 os.Args,退出码则通过 os.Exit 设置。

fmt.Println("Hello, World!")

Println 打印它的参数,在参数之间加空格,并在末尾加换行。这个名字以大写字母开头,是因为只有首字母大写的名字才会从包中导出。把 p 写成小写的 fmt.println 会导致编译错误。

打印的不止是字符串

Println 可以接收任意数量、任意类型的值。Printf 则让你自己控制格式:

%s 会被替换成字符串,%d 会被替换成整数。Printf 和 Print 不会自动换行,所以 \n 要你自己写。完整的格式动词表在 fmt.Printf 页面。

在你的电脑上运行

装好 Go 之后,把程序保存为空文件夹里的 main.go,然后运行:

go run main.go
Hello, World!

go run 会把文件编译成一个临时的二进制文件并运行它。要生成一个可以保留、可以复制到别处的二进制文件,就用 go build:

go mod init example.com/hello
go build
./hello
Hello, World!

go build 需要一个模块(也就是 go.mod 文件),由 go mod init 创建。生成的二进制文件以模块路径的最后一段命名,这里是 hello(在 Windows 上是 hello.exe)。run、build 和 install 的区别在 go run 和 go build 页面中讲解。

分号去哪了

Go 的语法里有分号,但你几乎从来不用自己输入。编译器会在每一行的末尾插入分号,只要这一行的最后一个记号可能结束一条语句:标识符、字面量、)、},以及 return 等少数几个关键字。正是这条规则,让其他语言里常见的这种写法在 Go 里行不通:

func main()
{
	fmt.Println("Hello, World!")
}
./main.go:6:1: syntax error: unexpected semicolon or newline before {

func main() 之后被插入了一个分号,所以下一行的 { 就成了错误。左花括号总是写在同一行。if、for、switch 以及其他所有代码块都遵循同样的规则。

最初的错误,逐一解释

下面是新手在第一个小时里会看到的报错,与 Go 1.24 打印的内容一字不差。

未使用的导入或变量。

package main

import (
	"fmt"
	"os"
)

func main() {
	x := 5
	fmt.Println("hi")
}
./main.go:5:2: "os" imported and not used
./main.go:9:2: declared and not used: x

这两个都是编译错误,不是警告。删掉这个导入或变量即可。如果调试时需要暂时保留某个变量,就把它赋给空白标识符:_ = x。

函数名写成了小写。

./main.go:6:6: undefined: fmt.println

未导出的名字在包外不可见。请使用 fmt.Println。

包名写错了。

package example.com/hello is not a main package

文件里写的是 package hello(或者 main 以外的任何名字),而你试图运行它。把它改成 package main。

缺少模块。

go: go.mod file not found in current directory or any parent directory; see 'go help modules'

go build 和 go run . 都基于模块工作。在这个文件夹里运行一次 go mod init example.com/hello 即可。直接指定文件名的 go run main.go 不需要模块也能运行。

代码格式化

Go 只有一种官方代码风格,由 gofmt 来统一。对你写的每个文件都运行它:

go fmt ./...

它使用 Tab 缩进,对齐注释和结构体字段,并统一空格。支持 Go 的编辑器会在保存时自动运行它。所有 Go 代码看起来都一样,所以没有什么需要配置,代码评审时也没有什么好争论的。

常见问题

Go 语言怎么写 hello world?

把下面的代码保存为 main.go:

package main

import "fmt"

func main() {
	fmt.Println("Hello, World!")
}

然后运行 go run main.go,它会打印 Hello, World!。

为什么 Go 程序需要 package main?

package main 告诉编译器这个包是一个可执行程序,而不是库。程序从 main 包的 main 函数开始运行。换成任何其他包名都会得到一个库,go run 会拒绝运行它,并提示“is not a main package”。

为什么 Go 的左花括号必须写在同一行?

Go 会在可能结束一条语句的行尾自动插入分号,func main() 之后也是如此。这样下一行的 { 就会开始一个独立的块,编译器会报告 syntax error: unexpected semicolon or newline before {。所以左花括号必须写在同一行。

Go 里的 fmt 是什么意思?

fmt 是标准库中负责格式化输入输出的包(名字是“format”的缩写)。fmt.Println 打印它的参数,参数之间用空格隔开,末尾加换行;fmt.Printf 则按格式字符串打印。

Coddy 编程语言插图

和 Coddy 一起学编程

开始