HelloWorld
- 创建项目文件夹
- 编写源码并运行程序
Go本身不严格限制代码的存储位置,但还是建议将Go的相关目录进行管理,避免项目混乱。创建项目目录后,在目录下创建main.go文件并··写入以下代码:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go Learn!")
}
保存main.go后,在终端中导航到文件所在目录,并执行以下命令构建程序:
go build main.go
执行完成后,同级目录下会出现一个名称为main的可执行文件,直接在终端中运行./main,则终端会输出:Hello, Go Learn!
Go程序的结构
package main
- 定义了一个包,这是Go中的基本组成单元,通常使用单个小写的单词命名
- 每个go源文件都对应一个包
main包在Go中是一个特殊的包,一个程序中仅允许存在一个名为main的包
import "fmt"
- 导入了一个名为
fmt的标准库,包在被导入后就可以使用库提供的函数 - 这里的
fmt指包的导入路径,表示标准库下的fmt目录,意味着导入该目录下的包 - 通常,导入路径的最后一个分段与包名相同,这很容易让人误解
import语句导入的是对应的包
func main() {
fmt.Println("Hello, Go Learn!")
}
-
第一行声明了一个名为
main的、没有任何参数和返回值的函数。 -
main函数是程序的入口点,Go编译器要求一个可执行程序的main包内必须定义一个main函数作为入口点,否则将导致编译失败。 -
Go要求所有函数体都必须由花括号包裹,按照管理,推荐左花括号
{与函数声明位于同一行,并用空格分隔。 -
fmt.Println("Hello, Go Learn!")完成了程序的核心任务:输出字符串到终端的标准输出。- 标准Go代码风格使用
Tab进行缩进 - 调用了
Pringln函数,这个函数位于Go标准库的fmt包中。 main函数之所以可以调用fmt包中的Println函数,是因为Println函数的首字母是大写的。- 传入的字符串就是执行程序后在终端标准输出上显示的内容,得益于Go源文件采用Unicode字符集,并以UTF8进行编码,保证了源代码和程序运行环境之间的字符集一致。
- 标准Go代码风格使用
在Go中,只有首字母为大写的标识符才是导出的(exported),此时对包外的代码可见;如果首字母小写,则标识符仅在其所属包内可见。
编译Go程序
Go是一种编译型语言,意味着只有在编译完成Go程序之后,才可以将生成的可执行程序分发给他人,并且可以在没有安装Go环境的目标机器上运行。
Go也借鉴了动态编程语言的优点,例如提供直接基于源码文件执行的功能。Go的run命令可以直接运行Go源文件,例如,可以使用以下命令直接运行main.go文件:
run main.go
这一命令更多地用于开发调试阶段,真正的交付物通常还是通过go build命令构建出可执行文件。
第一个Go module
Go module构架模式自Go 1.11版本正式引入,并逐步成为默认的包依赖管理和源码构建机制。
Go module的核心是go.mod文件,记录了module对第三方依赖的全部信息。
在main.go同级目录下新增一个go.mod,并写入以下内容:
## HelloWorld
- 创建项目文件夹
- 编写源码并运行程序
Go 本身不严格限制代码的存储位置,但仍建议对 Go 相关目录进行统一管理,避免项目混乱。创建项目目录后,在目录下创建 `main.go` 文件并写入以下代码:
```go
package main
import "fmt"
func main() {
fmt.Println("Hello, Go Learn!")
}
保存 main.go 后,在终端中导航到文件所在目录,并执行以下命令构建程序:
go build main.go
执行完成后,同级目录下会出现一个名为 main(Windows 下为 main.exe)的可执行文件。直接在终端中运行 ./main,终端会输出:Hello, Go Learn!
Go 程序的结构
package main
- 定义了一个包(package),这是 Go 中的基本组成单元,包名通常使用单个小写单词。
- 每个
.go源文件都必须声明所属包。 main包在 Go 中是一个特殊的包:当你构建可执行程序时,需要有一个package main,并且该包内必须包含func main()作为入口点。(一个工程中可以有多个main包,但通常对应多个可执行程序,位于不同目录。)
import "fmt"
- 导入标准库包
fmt,导入后即可使用该包提供的函数等导出成员。 - 这里的
fmt是包的导入路径(import path),标准库包的导入路径通常与包名一致。
func main() {
fmt.Println("Hello, Go Learn!")
}
- 第一行声明了一个名为
main的函数,没有参数也没有返回值。 main函数是可执行程序的入口点:main包内必须定义main函数,否则构建可执行文件会失败。- Go 要求函数体必须由花括号包裹;推荐将左花括号
{与函数声明放在同一行,并以空格分隔。 fmt.Println("Hello, Go Learn!")完成核心任务:向标准输出打印一行文本。- 标准 Go 代码风格使用 Tab 缩进(通常由
gofmt自动格式化)。 - 调用的是
Println函数,它位于 Go 标准库的fmt包中。 main能调用fmt.Println,是因为Println首字母大写,属于可导出标识符。- Go 源文件采用 UTF-8 编码,支持 Unicode 字符,因此可以稳定处理多语言文本。
- 标准 Go 代码风格使用 Tab 缩进(通常由
在 Go 中,只有首字母大写的标识符才是导出的(exported),对包外代码可见;首字母小写则仅在包内可见。
编译与运行 Go 程序
Go 是编译型语言:通常需要先编译生成可执行文件,再分发给他人运行;目标机器在多数情况下无需安装 Go(但需满足目标系统与架构匹配,并注意是否启用了 cgo 等依赖)。
同时,Go 也提供了便捷的开发期运行方式。可以使用 go run 直接编译并运行源文件,例如:
go run main.go
该命令常用于开发调试阶段;交付时通常使用 go build 生成可执行文件。
第一个 Go Module
Go Module 机制自 Go 1.11 引入,并在后续版本中成为默认的依赖管理与构建方式(建议始终在 module 模式下工作)。
Go Module 的核心是 go.mod 文件,用于声明模块信息与依赖版本。
在 main.go 同级目录下创建 go.mod,写入以下内容(示例):
module github.com/hxuanyu/hello-module
go 1.22
- 第一行声明模块路径(module path),用于唯一标识该模块。包的导入路径通常由
module path加上包所在子目录共同决定。 - 第二行是 Go 版本声明,表示该模块面向的语言版本(用于影响模块解析与部分构建行为)。应填写你实际使用或期望的 Go 版本;
1.24.11并不是一个有效的 Go 版本标识。
假设 main.go 内容如下:
package main
import (
"github.com/valyala/fasthttp"
"go.uber.org/zap"
)
var logger *zap.Logger
func init() {
logger, _ = zap.NewProduction()
}
func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
logger.Info("hello, go module", zap.ByteString("uri", ctx.RequestURI()))
}
func main() {
if err := fasthttp.ListenAndServe(":8080", fastHTTPHandler); err != nil {
logger.Fatal("server error", zap.Error(err))
}
}
该程序导入了 zap 与 fasthttp。在 module 模式下构建时,如果依赖尚未写入 go.mod(或本地缓存中没有对应依赖),可以执行以下命令自动解析并整理依赖:
go mod tidy
执行完成后,go.mod 会更新为包含直接依赖与必要的间接依赖(版本号以实际解析结果为准),例如:
module github.com/hxuanyu/hello-module
go 1.22
require (
github.com/valyala/fasthttp v1.68.0
go.uber.org/zap v1.27.0
)
同时会生成(或更新)go.sum 文件,用于记录依赖模块内容的校验信息(checksum),以验证下载内容的一致性与完整性。
总结
- 包(package)是 Go 的基本组成单元;所有 Go 代码都必须属于某个包。
- Go 源码可以导入其他包,并使用其中导出的类型、变量、函数与方法等;可执行程序的入口是
main包中的main函数。 - Go 程序通常先编译再分发运行;简单示例可用
go build main.go构建,用go run main.go便捷运行;复杂项目建议使用 Go Module 管理依赖并完成构建。module github.com/hxuanyu/hello-module
go 1.24.11
第一行声明了module的路径(module path),用于唯一标识此module。其中隐含了一种命名空间的概念,即每个包的导入路径由 module path 和包所在的子目录名共同决定。
第二行是Go版本标识符,表明建议使用Go 1.24.11或更高版本来编译本module代码。
假设main中的代码如下:
```go
package main
import (
"github.com/valyala/fasthttp"
"go.uber.org/zap"
)
var logger *zap.Logger
func init() {
logger, _ = zap.NewProduction()
}
func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
logger.Info("hello, go module", zap.ByteString("uri:", ctx.RequestURI()))
}
func main() {
err := fasthttp.ListenAndServe(":8080", fastHTTPHandler)
if err != nil {
return
}
}
这个main程序导入了zap包合fasthttp包,此时直接go build main.go,会编译报错,因为编译器在编译过程中找不到相关的依赖信息,对于复杂的go程序,往往会引入很多三方依赖包,这些三方依赖包的管理可以通过go.mod文件进行。可以执行以下命令自动整理依赖信息:
go mod tidy
执行完成后,go.mod文件内容发生了变化:
module github.com/hxuanyu/hello-module
go 1.24.11
require (
github.com/valyala/fasthttp v1.68.0
go.uber.org/zap v1.27.1
)
require (
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/klauspost/compress v1.18.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
)
工具自动添加了hellomodule的直接依赖和间接依赖,此时,go.mod文件已经记录了hellomodule的依赖包信息,在构件时,编译器可以根据依赖信息在本地依赖缓存中寻找对应的依赖包,并将它们一起进行构建操作。
此外,还多了一个go.sum文件,用来记录直接和间接依赖包的版本hash值,用来校验本地包的真实性。
总结
- Go包是Go的基本组成单元。一个Go程序由多个包构成,所有的Go代码都必须属于某个包。
- Go源码可以导入其他包,并使用其中导出的语法元素,如类型、变量、函数和方法等。
main函数是整个Go程序的入口点。 - Go源码需要先编译,再分发和运行。对于单个源文件,可以直接使用
go build命令加上源码文件名进行编译;对于复杂项目,需要借助Go module来管理依赖关系并完成构建过程。