Go > Packages and Modules > Creating Packages > Package initialization

Package Initialization in Go

Learn how packages are initialized in Go, including the use of the init function for setting up package state. Understand the order of initialization and how it impacts your code.

Basic Package Initialization

This code demonstrates a basic package with an init function. The init function is automatically executed when the package is imported. It's often used for initializing variables or setting up resources. Note the init function has no parameters and no return values. It's implicitly declared. The execution order is determined by the import order of the packages. The variable Version is initialized within the init function.

package mypackage

import "fmt"

var Version string

func init() {
    Version = "1.0.0"
    fmt.Println("mypackage initialized")
}

func MyFunction() {
    fmt.Println("Version:", Version)
}

Using the Package

This code demonstrates how to use the mypackage created earlier. When main imports mypackage, the init function within mypackage is executed before main's main function. The output will show 'mypackage initialized' before any other output from main.

package main

import "fmt"
import "./mypackage"

func main() {
	fmt.Println("main package started")
    mypackage.MyFunction()
	fmt.Println("main package finished")
}

Concepts Behind Package Initialization

Package initialization ensures that the necessary setup is performed before any part of the package is used. The init function is the core mechanism for performing this setup. The order of initialization is crucial: Package-level variables are initialized in the order they're declared, taking into account dependencies. Then, all init functions in the package are executed, also in the order they appear in the source files. Finally the main function of the main package is executed.

Real-Life Use Case

Consider a database connection package. The init function could establish the initial database connection, load configuration files, or perform database schema migrations before any code that uses the database is executed. Another common use case is registering a database driver with the database/sql package. This guarantees that the driver is available before any queries are executed.

Best Practices

  • Keep init functions simple and focused on essential setup tasks.
  • Avoid complex logic or long-running operations within init functions, as they can slow down application startup.
  • Be mindful of the order of initialization, especially when dealing with dependencies between packages.
  • Avoid init functions that depend on global state that may not be available yet.
  • Handle errors gracefully within init functions, potentially logging errors and exiting the program if a critical dependency fails to initialize.

Interview Tip

Be prepared to explain the order of package initialization in Go. Understand the difference between variable initialization and init function execution. Also, be aware of potential pitfalls, such as circular dependencies between packages.

When to Use Them

Use init functions for tasks that must be performed before any other code in the package can be executed. Examples include: setting up configuration parameters, registering drivers, and initializing global data structures.

Alternatives

Instead of relying solely on init functions, consider lazy initialization, where resources are initialized only when they're first needed. This can improve startup time and avoid unnecessary initialization if certain parts of the package are never used. Another approach is to use a dedicated initialization function that is explicitly called by the user of the package.

Pros

  • Guaranteed execution before other package code.
  • Automatic execution; no explicit call needed.
  • Useful for setting up global state and resources.

Cons

  • Can make dependencies less explicit.
  • Potential for hidden side effects.
  • Can slow down application startup if overused.
  • Difficult to test init functions in isolation.

FAQ

  • What happens if multiple init functions are defined in a single package?

    All init functions within a package are executed, in the order they appear in the source files. Go specification does not guarantee a specific order of execution across multiple files in the same package, however, they will be executed sequentially.
  • Can I pass arguments to an init function?

    No, init functions cannot accept arguments or return values. They are automatically executed by the Go runtime.
  • What happens if an init function causes a panic?

    If an init function panics, the program will terminate. It's important to handle errors gracefully within init functions to prevent unexpected program termination.