1.4 第一个Go程序与代码规范¶
学习目标¶
- 编写并运行第一个Go程序
- 理解Go程序的基本结构
- 掌握Go语言代码规范
- 学会包的概念与使用
- 了解注释规范与文档编写
1. Hello World程序¶
1.1 创建第一个程序¶
创建一个名为 hello.go 的文件:
1.2 运行程序¶
1.3 程序结构分析¶
package main // 1. 包声明
import "fmt" // 2. 导入语句
func main() { // 3. 主函数
fmt.Println("Hello, World!") // 4. 函数体
}
结构说明:
- package main:声明这是一个可执行程序
- import "fmt":导入fmt包用于格式化输出
- func main():程序入口函数
- fmt.Println():调用fmt包的Println函数
2. Go程序基本结构¶
2.1 完整程序示例¶
// 文件头注释:程序说明
// 这是一个演示Go程序结构的示例
package main
import (
"fmt" // 标准库
"os" // 标准库
"strings" // 标准库
"github.com/gin-gonic/gin" // 第三方库
)
// 全局变量
var (
appName = "MyApp"
appVersion = "1.0.0"
)
// 全局常量
const (
MaxRetries = 3
DefaultPort = 8080
)
// 自定义类型
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
// init函数:包初始化
func init() {
fmt.Println("Package initialized")
}
// 主函数
func main() {
fmt.Printf("%s v%s\n", appName, appVersion)
user := User{ID: 1, Name: "Alice"}
fmt.Printf("User: %+v\n", user)
}
2.2 程序执行顺序¶
package main
import "fmt"
var globalVar = initGlobalVar()
func initGlobalVar() string {
fmt.Println("1. 初始化全局变量")
return "global"
}
func init() {
fmt.Println("2. 执行init函数")
}
func main() {
fmt.Println("3. 执行main函数")
}
// 输出:
// 1. 初始化全局变量
// 2. 执行init函数
// 3. 执行main函数
3. Go语言代码规范¶
3.1 命名规范¶
包名规范¶
// 好的包名
package user
package http
package json
// 不好的包名
package userService // 避免驼峰命名
package User // 避免大写开头
package user_service // 避免下划线
变量命名¶
// 局部变量:驼峰命名
var userName string
var userAge int
var isActive bool
// 全局变量:首字母大写表示导出
var UserCount int
var MaxConnections int
// 常量:全大写或驼峰
const MaxRetries = 3
const DefaultTimeout = 30 * time.Second
// 私有常量
const maxRetries = 3
函数命名¶
// 导出函数:首字母大写
func GetUser(id int) (*User, error) {
// ...
}
// 私有函数:首字母小写
func validateUser(user *User) error {
// ...
}
// 接口命名:通常以-er结尾
type Reader interface {
Read([]byte) (int, error)
}
type Writer interface {
Write([]byte) (int, error)
}
结构体命名¶
// 结构体:首字母大写表示导出
type User struct {
ID int `json:"id"` // 导出字段
Name string `json:"name"` // 导出字段
password string `json:"-"` // 私有字段
}
// 方法命名
func (u *User) GetName() string {
return u.Name
}
func (u *User) setPassword(pwd string) {
u.password = pwd
}
3.2 代码格式规范¶
缩进与空格¶
// 使用Tab进行缩进,不使用空格
func main() {
if true {
fmt.Println("使用Tab缩进")
}
}
// 操作符前后加空格
result := a + b
if x > 0 && y < 10 {
// ...
}
// 逗号后加空格
values := []int{1, 2, 3, 4, 5}
fmt.Printf("Hello, %s!\n", name)
行长度与换行¶
// 行长度控制在80-120字符以内
func processUserData(userID int, userName string, userEmail string,
userAge int, isActive bool) error {
// ...
}
// 长参数列表换行对齐
user := &User{
ID: 1,
Name: "Alice",
Email: "alice@example.com",
Age: 25,
}
大括号位置¶
// 左大括号不换行
if condition {
// ...
} else {
// ...
}
func myFunction() {
// ...
}
type MyStruct struct {
field1 string
field2 int
}
3.3 导入规范¶
package main
import (
// 1. 标准库
"context"
"fmt"
"net/http"
"os"
"time"
// 2. 第三方库
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
// 3. 项目内部包
"myproject/internal/config"
"myproject/internal/service"
"myproject/pkg/utils"
)
导入别名¶
import (
"database/sql"
// 别名导入
mysqlDriver "github.com/go-sql-driver/mysql"
// 点导入(谨慎使用)
. "github.com/onsi/ginkgo"
// 空白导入(仅执行init函数)
_ "github.com/go-sql-driver/mysql"
)
4. 包的概念与使用¶
4.1 包的基本概念¶
// 包声明必须在文件开头
package utils
// 同一个包内的文件可以互相访问私有成员
func publicFunction() { // 导出函数
privateFunction() // 可以调用私有函数
}
func privateFunction() { // 私有函数
// ...
}
4.2 包的组织结构¶
myproject/
├── main.go // package main
├── utils/ // package utils
│ ├── string.go // package utils
│ └── math.go // package utils
├── models/ // package models
│ ├── user.go // package models
│ └── product.go // package models
└── handlers/ // package handlers
├── user.go // package handlers
└── product.go // package handlers
4.3 包的使用示例¶
utils/string.go
package utils
import "strings"
// 导出函数:首字母大写
func Capitalize(s string) string {
if len(s) == 0 {
return s
}
return strings.ToUpper(s[:1]) + s[1:]
}
// 私有函数:首字母小写
func reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
main.go
package main
import (
"fmt"
"myproject/utils" // 导入自定义包
)
func main() {
result := utils.Capitalize("hello world")
fmt.Println(result) // 输出:Hello world
// result := utils.reverse("hello") // 编译错误:无法访问私有函数
}
4.4 init函数¶
package database
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
var DB *sql.DB
// init函数在包被导入时自动执行
func init() {
var err error
DB, err = sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
if err = DB.Ping(); err != nil {
log.Fatal("Failed to ping database:", err)
}
log.Println("Database connection established")
}
5. 注释规范与文档编写¶
5.1 注释类型¶
单行注释¶
多行注释¶
/*
这是多行注释
可以跨越多行
通常用于版权声明或大段说明
*/
/*
Package utils provides utility functions for string and math operations.
This package includes commonly used helper functions that can be reused
across different parts of the application.
*/
package utils
5.2 文档注释规范¶
包文档¶
// Package user provides user management functionality.
//
// This package includes user registration, authentication,
// and profile management features.
//
// Example usage:
//
// user := &User{Name: "Alice", Email: "alice@example.com"}
// if err := user.Save(); err != nil {
// log.Fatal(err)
// }
//
package user
函数文档¶
// GetUser retrieves a user by ID from the database.
//
// It returns the user object if found, or an error if the user
// doesn't exist or if there's a database connection issue.
//
// Example:
//
// user, err := GetUser(123)
// if err != nil {
// log.Printf("Error getting user: %v", err)
// return
// }
// fmt.Printf("User: %s\n", user.Name)
//
func GetUser(id int) (*User, error) {
// 实现细节...
}
类型文档¶
// User represents a user in the system.
//
// Each user has a unique ID, name, and email address.
// The password field is not exported for security reasons.
type User struct {
ID int `json:"id" db:"id"` // 用户唯一标识
Name string `json:"name" db:"name"` // 用户姓名
Email string `json:"email" db:"email"` // 邮箱地址
password string `json:"-" db:"password"` // 密码(私有)
}
// String returns a string representation of the user.
func (u User) String() string {
return fmt.Sprintf("User{ID: %d, Name: %s, Email: %s}",
u.ID, u.Name, u.Email)
}
常量和变量文档¶
// DefaultTimeout is the default timeout for HTTP requests.
const DefaultTimeout = 30 * time.Second
// ErrUserNotFound is returned when a user is not found in the database.
var ErrUserNotFound = errors.New("user not found")
// Configuration holds application configuration.
var Config = struct {
Port int // 服务端口
Database string // 数据库连接字符串
Debug bool // 调试模式
}{
Port: 8080,
Database: "localhost:5432",
Debug: false,
}
5.3 生成文档¶
# 查看包文档
go doc fmt
go doc fmt.Println
# 查看自定义包文档
go doc ./utils
go doc utils.Capitalize
# 生成HTML文档
godoc -http=:6060
# 在浏览器中访问 http://localhost:6060
6. 实践示例¶
6.1 完整的用户管理包¶
models/user.go
// Package models provides data models for the application.
package models
import (
"errors"
"fmt"
"regexp"
)
// 常见错误定义
var (
ErrInvalidEmail = errors.New("invalid email address")
ErrEmptyName = errors.New("name cannot be empty")
)
// User represents a user in the system.
//
// Each user must have a valid email address and non-empty name.
// The ID is automatically assigned when the user is saved.
type User struct {
ID int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Email string `json:"email" db:"email"`
}
// NewUser creates a new user with the given name and email.
//
// It validates the input parameters and returns an error if
// validation fails.
func NewUser(name, email string) (*User, error) {
user := &User{
Name: name,
Email: email,
}
if err := user.Validate(); err != nil {
return nil, err
}
return user, nil
}
// Validate checks if the user data is valid.
//
// It returns an error if the name is empty or the email
// address is not in a valid format.
func (u *User) Validate() error {
if u.Name == "" {
return ErrEmptyName
}
emailRegex := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
if !emailRegex.MatchString(u.Email) {
return ErrInvalidEmail
}
return nil
}
// String returns a string representation of the user.
func (u User) String() string {
return fmt.Sprintf("User{ID: %d, Name: %s, Email: %s}",
u.ID, u.Name, u.Email)
}
main.go
package main
import (
"fmt"
"log"
"myproject/models"
)
func main() {
// 创建用户
user, err := models.NewUser("Alice", "alice@example.com")
if err != nil {
log.Fatal("创建用户失败:", err)
}
fmt.Printf("创建用户成功: %s\n", user)
// 测试无效邮箱
invalidUser, err := models.NewUser("Bob", "invalid-email")
if err != nil {
fmt.Printf("预期的错误: %v\n", err)
} else {
fmt.Printf("意外创建了用户: %s\n", invalidUser)
}
}
7. 代码规范工具¶
7.1 gofmt - 代码格式化¶
7.2 goimports - 导入管理¶
# 安装
go install golang.org/x/tools/cmd/goimports@latest
# 自动管理导入并格式化
goimports -w main.go
# 查看差异
goimports -d main.go
7.3 golint - 代码规范检查¶
# 安装
go install golang.org/x/lint/golint@latest
# 检查代码规范
golint ./...
# 示例输出
# main.go:10:1: exported function GetUser should have comment or be unexported
本节小结¶
通过本节学习,您应该掌握了Go程序的基本结构、代码规范和文档编写方法。良好的代码规范不仅提高代码可读性,还有助于团队协作和项目维护。
思考题¶
- 为什么Go语言强调代码格式的统一性?
- 在什么情况下应该使用init函数?
- 如何为开源项目编写高质量的文档注释?