Packages and Modules
## Learning Objectives
- Understand Go packages
- Create and use modules
- Import packages correctly
- Organize code effectively
- Work with the go.mod file
## Packages
### What is a Package?
A package is a collection of Go source files in the same directory.
### Package Declaration
```go
package main // Executable package
package utils // Library package
```
### Package Names
```go
package main // Executable
package math // Library (math functions)
```
## Project Structure
### Standard Layout
```text
myproject/
├── go.mod
├── main.go
├── utils/
│ └── helpers.go
└── models/
└── user.go
```
### Package Names Match Directory
```text
utils/helpers.go -> package utils
models/user.go -> package models
```
## Modules
### What is a Module?
A module is a collection of Go packages versioned together.
### Creating a Module
```bash
go mod init example.com/myproject
```
### go.mod File
```go
module example.com/myproject
go 1.21
require (
github.com/some/pkg v1.2.3
)
```
## Imports
### Basic Import
```go
import "fmt"
func main() {
fmt.Println("Hello")
}
```
### Multiple Imports
```go
import (
"fmt"
"math"
"strings"
)
func main() {
fmt.Println(math.pi)
fmt.Println(strings.ToUpper("hello"))
}
```
### Import with Alias
```go
import (
f "fmt" // Alias
m "math" // Alias
)
func main() {
f.Println(m.pi)
}
```
### Dot Import
```go
import . "fmt" // Avoid: pollutes namespace
func main() {
Println("Hello") // No prefix
}
```
### Blank Import
```go
import _ "database/sql" // Register driver only
```
## Creating Packages
### utils/helpers.go
```go
package utils
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)
}
func UpperCase(s string) string {
return strings.ToUpper(s)
}
```
### main.go
```go
package main
import (
"fmt"
"example.com/myproject/utils"
)
func main() {
fmt.Println(utils.Reverse("hello"))
fmt.Println(utils.UpperCase("hello"))
}
```
## Visibility Rules
### Exported vs Unexported
```go
package utils
const MaxSize = 100 // Exported (capitalized)
const minSize = 10 // Unexported (lowercase)
func PublicFunc() {} // Exported
func privateFunc() {} // Unexported
```
### Access from Outside
```go
import "example.com/myproject/utils"
utils.MaxSize // OK
utils.PublicFunc() // OK
// utils.minSize // ERROR: not accessible
// utils.privateFunc() // ERROR: not accessible
```
## init Function
### Automatic Execution
```go
package utils
var config string
func init() {
config = "default"
}
```
### Multiple init Functions
```go
package main
func init() {
fmt.Println("First init")
}
func init() {
fmt.Println("Second init")
}
```
### init Order
1. Imported packages initialized first
2. Package-level variables initialized
3. init() functions run in declaration order
## Standard Library Packages
### Common Imports
```go
import "fmt" // Formatted I/O
import "os" // Operating system
import "io" // I/O primitives
import "bufio" // Buffered I/O
import "strings" // String utilities
import "strconv" // String conversion
import "time" // Time operations
import "math" // Math functions
import "log" // Logging
import "errors" // Error handling
```
### net/http
```go
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello"))
})
http.ListenAndServe(":8080", nil)
}
```
### encoding/json
```go
import "encoding/json"
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := Person{Name: "Alice", Age: 30}
jsonBytes, _ := json.Marshal(p)
fmt.Println(string(jsonBytes))
}
```
## External Packages
### go get
```bash
go get github.com/gin-gonic/gin
go get github.com/stretchr/testify
```
### Version Specification
```go
require (
github.com/gin-gonic/gin v1.9.1
github.com/stretchr/testify v1.8.4
)
```
### go.sum
Automatically generated and tracked.
## Module Commands
### Common Commands
```bash
go mod init example.com/project # Initialize module
go mod tidy # Clean up dependencies
go mod download # Download dependencies
go mod graph # Show dependency graph
go mod why github.com/pkg # Explain why dependency
```
### go mod tidy
```bash
# Removes unused dependencies
# Adds missing dependencies
# Updates go.mod and go.sum
go mod tidy
```
## vendoring
### Create Vendor
```bash
go mod vendor
```
### Directory Structure
```text
project/
├── go.mod
├── go.sum
├── vendor/
│ └── github.com/
│ └── pkg/
│ └── *.go
└── main.go
```
### Using Vendor
```bash
go build -mod=vendor
```
## Testing Packages
### Basic Test
```go
package utils
func Add(a, b int) int {
return a + b
}
```
### utils_test.go
```go
package utils
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2, 3) = %d, want 5", result)
}
}
```
### Run Tests
```bash
go test ./... # Run all tests
go test -v ./... # Verbose output
go test -cover ./... # Show coverage
```
## Code Organization Tips
### Single Module per Project
```text
myproject/
├── go.mod
├── cmd/
│ └── app/
│ └── main.go
├── internal/
│ ├── handlers/
│ ├── models/
│ └── services/
├── pkg/
│ └── utils/
└── api/
```
### internal Package
Packages named `internal` are only importable by parent directories.
```text
myproject/
├── internal/
│ └── utils/
│ └── helpers.go
└── cmd/
└── app/
└── main.go // Can import internal/utils
```
## Summary
- Packages group related Go source files
- Modules are versioned collections of packages
- `go.mod` defines module name and dependencies
- Exported identifiers start with uppercase
- `init()` runs automatically before main
- Use `go get` to add dependencies
- `go mod tidy` manages dependencies
- Test files end with `_test.go`
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →