flyfei

包(package)与导入(import)

1. 语法讲解

包定义

每个Go源文件必须属于一个包,包声明在第一行:

package 包名

导入机制

import (
    "fmt"
    "第三方包"
    "项目内部包"
)

多种导入方式:

可见性规则

2. 应用场景

真实业务场景:电商微服务项目结构 大型电商平台采用微服务架构,不同功能模块拆分为独立包:

这种分包方式提高代码可维护性,支持团队协作开发。

3. 编程实例

项目结构示例

ecommerce/
├── main.go
├── go.mod
├── common/
│   ├── logger.go
│   └── database.go
├── user/
│   ├── user.go
│   └── user_service.go
├── product/
│   ├── product.go
│   └── product_service.go
└── order/
    ├── order.go
    └── order_service.go

具体代码实现

common/logger.go

package common

import (
    "fmt"
    "log"
    "os"
    "time"
)

// 导出的大写开头函数
func NewLogger(prefix string) *log.Logger {
    return log.New(os.Stdout, prefix+" ", log.Ldate|log.Ltime)
}

func LogOperation(operation string) {
    fmt.Printf("[%s] 操作: %s\n", time.Now().Format("2006-01-02 15:04:05"), operation)
}

// 未导出的小写开头函数,仅在包内使用
func formatLogMessage(level, message string) string {
    return fmt.Sprintf("[%s] %s: %s", time.Now().Format("15:04:05"), level, message)
}

user/user.go

package user

import (
    "fmt"
    "yourproject/common"
)

// 导出结构体
type User struct {
    ID       int
    Name     string
    Email    string
    password string // 未导出字段,包外不可访问
}

// 导出方法
func (u *User) DisplayInfo() {
    fmt.Printf("用户ID: %d, 姓名: %s, 邮箱: %s\n", u.ID, u.Name, u.Email)
}

// 未导出方法
func (u *User) validatePassword() bool {
    return len(u.password) >= 6
}

// 导出函数
func CreateUser(name, email, password string) *User {
    common.LogOperation("创建用户")
    
    user := &User{
        ID:       generateID(),
        Name:     name,
        Email:    email,
        password: password,
    }
    
    if !user.validatePassword() {
        fmt.Println("密码强度不足")
        return nil
    }
    
    return user
}

// 未导出函数
func generateID() int {
    return int(time.Now().Unix())
}

user/user_service.go

package user

import "fmt"

type UserService struct {
    users []*User
}

func NewUserService() *UserService {
    return &UserService{
        users: make([]*User, 0),
    }
}

func (us *UserService) AddUser(user *User) {
    if user != nil {
        us.users = append(us.users, user)
        fmt.Printf("用户 %s 添加成功\n", user.Name)
    }
}

func (us *UserService) FindUserByID(id int) *User {
    for _, user := range us.users {
        if user.ID == id {
            return user
        }
    }
    return nil
}

func (us *UserService) ListAllUsers() {
    fmt.Println("=== 所有用户 ===")
    for _, user := range us.users {
        user.DisplayInfo()
    }
}

product/product.go

package product

import "yourproject/common"

type Product struct {
    ID    int
    Name  string
    Price float64
    Stock int
}

type ProductService struct {
    products []*Product
    logger   *log.Logger
}

func NewProductService() *ProductService {
    return &ProductService{
        products: make([]*Product, 0),
        logger:   common.NewLogger("[PRODUCT]"),
    }
}

func (ps *ProductService) AddProduct(name string, price float64, stock int) {
    product := &Product{
        ID:    len(ps.products) + 1,
        Name:  name,
        Price: price,
        Stock: stock,
    }
    
    ps.products = append(ps.products, product)
    ps.logger.Printf("商品添加成功: %s, 价格: %.2f, 库存: %d", name, price, stock)
}

func (ps *ProductService) FindProductByID(id int) *Product {
    for _, product := range ps.products {
        if product.ID == id {
            return product
        }
    }
    return nil
}

main.go

package main

import (
    "fmt"
    "yourproject/user"
    "yourproject/product"
    "yourproject/common"
)

func main() {
    fmt.Println("=== 电商系统启动 ===\n")
    
    // 初始化服务
    userService := user.NewUserService()
    productService := product.NewProductService()
    
    // 用户管理演示
    fmt.Println("1. 用户管理")
    common.LogOperation("开始创建用户")
    
    user1 := user.CreateUser("张三", "zhangsan@example.com", "password123")
    user2 := user.CreateUser("李四", "lisi@example.com", "abc") // 密码太短,创建失败
    
    if user1 != nil {
        userService.AddUser(user1)
    }
    if user2 != nil {
        userService.AddUser(user2)
    }
    
    userService.ListAllUsers()
    
    // 商品管理演示
    fmt.Println("\n2. 商品管理")
    productService.AddProduct("iPhone 14", 5999.00, 100)
    productService.AddProduct("MacBook Pro", 12999.00, 50)
    
    // 查找商品
    foundProduct := productService.FindProductByID(1)
    if foundProduct != nil {
        fmt.Printf("找到商品: %s, 价格: %.2f\n", foundProduct.Name, foundProduct.Price)
    }
    
    fmt.Println("\n=== 系统运行完成 ===")
}

4. 其他用法

初始化函数init()

package config

import (
    "fmt"
    "os"
)

var (
    DatabaseURL string
    APIKey      string
)

// init函数在包被导入时自动执行
func init() {
    fmt.Println("初始化配置包...")
    
    DatabaseURL = getEnv("DATABASE_URL", "localhost:5432")
    APIKey = getEnv("API_KEY", "default-key")
    
    fmt.Printf("数据库URL: %s\n", DatabaseURL)
}

func getEnv(key, defaultValue string) string {
    if value := os.Getenv(key); value != "" {
        return value
    }
    return defaultValue
}

别名导入和点导入

package main

import (
    "fmt"
    "math"
    m "math"           // 别名导入
    . "math/rand"      // 点导入 - 可直接使用包内函数
    _ "image/png"      // 空白导入 - 只执行init函数
)

func main() {
    // 标准导入
    fmt.Printf("标准导入: π = %.2f\n", math.Pi)
    
    // 别名导入
    fmt.Printf("别名导入: π = %.2f\n", m.Pi)
    
    // 点导入 - 可直接使用Intn,不需要rand.Intn
    fmt.Printf("点导入随机数: %d\n", Intn(100))
    
    // 空白导入的包无法直接使用,但会执行其init函数
}

包作用域和变量共享

package cache

import "sync"

// 包级变量 - 在包内所有文件中可见
var (
    cache = make(map[string]interface{})
    mutex = &sync.RWMutex{}
    hitCount   int // 包内可见
    MissCount  int // 导出,包外可见
)

// 导出函数
func Get(key string) interface{} {
    mutex.RLock()
    defer mutex.RUnlock()
    
    if value, exists := cache[key]; exists {
        hitCount++
        return value
    }
    MissCount++
    return nil
}

func Set(key string, value interface{}) {
    mutex.Lock()
    defer mutex.Unlock()
    cache[key] = value
}

// 包内使用的辅助函数
func clearExpired() {
    // 清理过期缓存逻辑
    mutex.Lock()
    defer mutex.Unlock()
    // 实现清理逻辑...
}

// 获取缓存统计信息
func GetStats() map[string]int {
    mutex.RLock()
    defer mutex.RUnlock()
    
    return map[string]int{
        "hit_count":  hitCount,
        "miss_count": MissCount,
        "total_size": len(cache),
    }
}

5. 课时总结