Lesson 10 of 12

Packages, Modules & the Standard Library

Learn how Go code is organized into and , and how to use the . A single go.mod file and the go command handle building and dependencies.

Bash
# Start a module — the path is normally the repo URL
go mod init github.com/you/myapp

# Add a dependency (or just import it and run go mod tidy)
go get github.com/google/uuid
go mod tidy          # add what is imported, remove what is not

go run ./cmd/server  # compile and run
go build ./...       # build everything
go test ./...        # test everything
go vet ./...         # catch suspicious constructs
gofmt -w .           # formatting is not a debate in Go

# A conventional layout
# myapp/
#   go.mod
#   cmd/server/main.go       package main — the entry point
#   internal/store/store.go  importable ONLY inside this module
#   pkg/api/client.go        intended for outside consumers
#   go.sum                   checksums, commit this file
Go
// internal/store/store.go
package store          // package name = directory name, lowercase, no underscores

import "errors"

// Exported: capital letter. Unexported: lowercase, package-private.
var ErrMissing = errors.New("store: key missing")

type Store struct {
	data map[string]string     // unexported field — callers cannot touch it
}

func New() *Store {            // constructor convention: New / NewX
	return &Store{data: make(map[string]string)}
}

func (s *Store) Set(key, value string) { s.data[key] = value }

func (s *Store) Get(key string) (string, error) {
	v, ok := s.data[key]
	if !ok {
		return "", ErrMissing
	}
	return v, nil
}

// cmd/server/main.go
package main

import (
	"fmt"
	"github.com/you/myapp/internal/store"
)

func main() {
	s := store.New()
	s.Set("greeting", "hello")
	v, _ := s.Get("greeting")
	fmt.Println(v)
}
Go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strings"
	"time"
)

type Todo struct {
	ID    int    `json:"id"`
	Title string `json:"title"`
	Done  bool   `json:"done,omitempty"`   // struct tags control JSON names
}

func main() {
	// encoding/json
	data, _ := json.Marshal(Todo{ID: 1, Title: "Learn Go"})
	fmt.Println(string(data))               // {"id":1,"title":"Learn Go"}

	var t Todo
	json.Unmarshal([]byte(`{"id":2,"title":"Ship it","done":true}`), &t)

	// net/http server in six lines — no framework required
	mux := http.NewServeMux()
	mux.HandleFunc("GET /todos/{id}", func(w http.ResponseWriter, r *http.Request) {
		id := r.PathValue("id")
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(Todo{ID: 1, Title: "todo " + id})
	})
	srv := &http.Server{Addr: ":8080", Handler: mux, ReadTimeout: 5 * time.Second}
	go srv.ListenAndServe()

	// strings, os and friends
	fmt.Println(strings.Join([]string{"a", "b"}, "-"))
	fmt.Println(strings.HasPrefix("golang", "go"))
	fmt.Println(os.Getenv("HOME"))
}
Finished reading?Mark it done to track your progress.

Tip: use the ← and → keys to move between lessons.