叩町

叩町

【Go】第一个Go程序

go
13
2025-12-18
【Go】第一个Go程序

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中,只有首字母为大写的标识符才是导出的(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,并写入以下内容:

module github.com/hxuanyu/hello-module

go 1.24.11

第一行声明了module的路径(module path),用于唯一标识此module。其中隐含了一种命名空间的概念,即每个包的导入路径由 module path 和包所在的子目录名共同决定。

第二行是Go版本标识符,表明建议使用Go 1.24.11或更高版本来编译本module代码。

假设main中的代码如下:

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来管理依赖关系并完成构建过程。
  • 2