In Go, a package is a collection of source files in the same directory that declare the same package name. Packages are the building blocks for organizing and reusing Go code. The main package is special because it defines a standalone executable. All other packages are used to group functionality.

The import statement allows you to use functionality defined in other packages. Go enforces a clear separation between internal and external dependencies, which helps maintain code clarity and avoid naming conflicts. Understanding how to effectively use and manage packages is essential for writing maintainable Go applications.

Creating and Using Packages

To create a package, define a directory with a consistent package name and a set of .go files. For example, let’s create a simple math utility package.

math/
├── math.go
└── math_test.go

In math.go, define a package named math and a function:

package math

// Add adds two integers and returns the result.
func Add(a, b int) int {
    return a + b
}

Now, create a new Go file in a different directory to use the math package:

package main

import (
    "fmt"
    "path/to/math" // Adjust path based on your module
)

func main() {
    result := math.Add(3, 4)
    fmt.Println("Result:", result) // Output: Result: 7
}

This example demonstrates how to import and use functions from another package. The import path should match the package structure defined in your Go module.

Best Practices for Package Management

When working with Go packages, follow these best practices to ensure maintainability and scalability:

  1. Use meaningful package names. Names should be concise and describe the functionality (e.g., math, utils).
  2. Export identifiers with uppercase names. Go uses case sensitivity for exporting; functions and variables with uppercase initials are exported.
  3. Avoid using dot imports. While import . "package" can reduce verbosity, it may lead to confusion and naming conflicts.
  4. Keep packages focused. Each package should encapsulate a specific concern or functionality.
  5. Use the go mod tool for dependency management. Go modules simplify versioning and dependency resolution.

Internal vs. External Packages

Go provides a special mechanism for managing internal access using the internal directory. Files in a directory named internal are only accessible to packages within the same module. This is useful for organizing code with restricted visibility.

For example:

myapp/
├── main.go
├── internal/
│   └── logger/
│       └── logger.go

In logger.go, define a logging function:

package logger

import "fmt"

// Log prints a message to the console.
func Log(msg string) {
    fmt.Println("LOG:", msg)
}

In main.go, import and use the logger package:

package main

import (
    "myapp/internal/logger"
)

func main() {
    logger.Log("Application started")
}

This structure ensures that the logger package is accessible only within the myapp module.

Comparing Go Package Features

FeatureDescription
package mainDefines an executable.
package nameGroups related functionality.
import "path"Imports functions, types, and variables from another package.
internal/ directoryRestricts access to packages within the same module.
go mod initInitializes a new Go module.
go mod tidyCleans up unused dependencies.

Learn more with useful resources