Add Golang skill and reference materials

- Introduced a new skill for Golang, providing comprehensive guidance on writing, debugging, and best practices for Go programming.
- Added reference materials including effective Go guidelines, common patterns, and a quick reference cheat sheet to support users in Go development.
- Created a skill creator guide to assist in developing new skills with structured templates and resource management.
- Implemented scripts for skill initialization and packaging to streamline the skill creation process.
This commit is contained in:
2025-11-04 12:36:36 +00:00
parent cefd0a98e7
commit fa71e9e334
18 changed files with 2858 additions and 110 deletions

View File

@@ -0,0 +1,649 @@
# Go Common Patterns and Idioms
## Design Patterns
### Functional Options Pattern
Used for configuring objects with many optional parameters:
```go
type Server struct {
host string
port int
timeout time.Duration
maxConn int
}
type Option func(*Server)
func WithHost(host string) Option {
return func(s *Server) {
s.host = host
}
}
func WithPort(port int) Option {
return func(s *Server) {
s.port = port
}
}
func WithTimeout(timeout time.Duration) Option {
return func(s *Server) {
s.timeout = timeout
}
}
func NewServer(opts ...Option) *Server {
// Set defaults
s := &Server{
host: "localhost",
port: 8080,
timeout: 30 * time.Second,
maxConn: 100,
}
// Apply options
for _, opt := range opts {
opt(s)
}
return s
}
// Usage
srv := NewServer(
WithHost("example.com"),
WithPort(443),
WithTimeout(60 * time.Second),
)
```
### Builder Pattern
For complex object construction:
```go
type HTTPRequest struct {
method string
url string
headers map[string]string
body []byte
}
type RequestBuilder struct {
request *HTTPRequest
}
func NewRequestBuilder() *RequestBuilder {
return &RequestBuilder{
request: &HTTPRequest{
headers: make(map[string]string),
},
}
}
func (b *RequestBuilder) Method(method string) *RequestBuilder {
b.request.method = method
return b
}
func (b *RequestBuilder) URL(url string) *RequestBuilder {
b.request.url = url
return b
}
func (b *RequestBuilder) Header(key, value string) *RequestBuilder {
b.request.headers[key] = value
return b
}
func (b *RequestBuilder) Body(body []byte) *RequestBuilder {
b.request.body = body
return b
}
func (b *RequestBuilder) Build() *HTTPRequest {
return b.request
}
// Usage
req := NewRequestBuilder().
Method("POST").
URL("https://api.example.com").
Header("Content-Type", "application/json").
Body([]byte(`{"key":"value"}`)).
Build()
```
### Singleton Pattern
Thread-safe singleton using sync.Once:
```go
type Database struct {
conn *sql.DB
}
var (
instance *Database
once sync.Once
)
func GetDatabase() *Database {
once.Do(func() {
conn, err := sql.Open("postgres", "connection-string")
if err != nil {
log.Fatal(err)
}
instance = &Database{conn: conn}
})
return instance
}
```
### Factory Pattern
```go
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string { return "Woof!" }
type Cat struct{}
func (c Cat) Speak() string { return "Meow!" }
type AnimalFactory struct{}
func (f *AnimalFactory) CreateAnimal(animalType string) Animal {
switch animalType {
case "dog":
return &Dog{}
case "cat":
return &Cat{}
default:
return nil
}
}
```
### Strategy Pattern
```go
type PaymentStrategy interface {
Pay(amount float64) error
}
type CreditCard struct {
number string
}
func (c *CreditCard) Pay(amount float64) error {
fmt.Printf("Paying %.2f using credit card %s\n", amount, c.number)
return nil
}
type PayPal struct {
email string
}
func (p *PayPal) Pay(amount float64) error {
fmt.Printf("Paying %.2f using PayPal account %s\n", amount, p.email)
return nil
}
type PaymentContext struct {
strategy PaymentStrategy
}
func (pc *PaymentContext) SetStrategy(strategy PaymentStrategy) {
pc.strategy = strategy
}
func (pc *PaymentContext) ExecutePayment(amount float64) error {
return pc.strategy.Pay(amount)
}
```
## Concurrency Patterns
### Worker Pool
```go
func worker(id int, jobs <-chan Job, results chan<- Result) {
for job := range jobs {
result := processJob(job)
results <- result
}
}
func WorkerPool(numWorkers int, jobs []Job) []Result {
jobsChan := make(chan Job, len(jobs))
results := make(chan Result, len(jobs))
// Start workers
for w := 1; w <= numWorkers; w++ {
go worker(w, jobsChan, results)
}
// Send jobs
for _, job := range jobs {
jobsChan <- job
}
close(jobsChan)
// Collect results
var output []Result
for range jobs {
output = append(output, <-results)
}
return output
}
```
### Pipeline Pattern
```go
func generator(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func main() {
// Create pipeline
c := generator(2, 3, 4)
out := square(c)
// Consume output
for result := range out {
fmt.Println(result)
}
}
```
### Fan-Out, Fan-In
```go
func fanOut(in <-chan int, n int) []<-chan int {
channels := make([]<-chan int, n)
for i := 0; i < n; i++ {
channels[i] = worker(in)
}
return channels
}
func worker(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- expensiveOperation(n)
}
close(out)
}()
return out
}
func fanIn(channels ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
wg.Add(len(channels))
for _, c := range channels {
go func(ch <-chan int) {
defer wg.Done()
for n := range ch {
out <- n
}
}(c)
}
go func() {
wg.Wait()
close(out)
}()
return out
}
```
### Timeout Pattern
```go
func DoWithTimeout(timeout time.Duration) (result string, err error) {
done := make(chan struct{})
go func() {
result = expensiveOperation()
close(done)
}()
select {
case <-done:
return result, nil
case <-time.After(timeout):
return "", fmt.Errorf("operation timed out after %v", timeout)
}
}
```
### Graceful Shutdown
```go
func main() {
server := &http.Server{Addr: ":8080"}
// Start server in goroutine
go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()
// Wait for interrupt signal
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down server...")
// Graceful shutdown with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
log.Println("Server exiting")
}
```
### Rate Limiting
```go
func rateLimiter(rate time.Duration) <-chan time.Time {
return time.Tick(rate)
}
func main() {
limiter := rateLimiter(200 * time.Millisecond)
for req := range requests {
<-limiter // Wait for rate limiter
go handleRequest(req)
}
}
```
### Circuit Breaker
```go
type CircuitBreaker struct {
maxFailures int
timeout time.Duration
failures int
lastFail time.Time
state string
mu sync.Mutex
}
func (cb *CircuitBreaker) Call(fn func() error) error {
cb.mu.Lock()
defer cb.mu.Unlock()
if cb.state == "open" {
if time.Since(cb.lastFail) > cb.timeout {
cb.state = "half-open"
} else {
return fmt.Errorf("circuit breaker is open")
}
}
err := fn()
if err != nil {
cb.failures++
cb.lastFail = time.Now()
if cb.failures >= cb.maxFailures {
cb.state = "open"
}
return err
}
cb.failures = 0
cb.state = "closed"
return nil
}
```
## Error Handling Patterns
### Error Wrapping
```go
func processFile(filename string) (err error) {
data, err := readFile(filename)
if err != nil {
return fmt.Errorf("failed to process file %s: %w", filename, err)
}
if err := validate(data); err != nil {
return fmt.Errorf("validation failed for %s: %w", filename, err)
}
return nil
}
```
### Sentinel Errors
```go
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrInvalidInput = errors.New("invalid input")
)
func FindUser(id int) (*User, error) {
user, exists := users[id]
if !exists {
return nil, ErrNotFound
}
return user, nil
}
// Check error
user, err := FindUser(123)
if errors.Is(err, ErrNotFound) {
// Handle not found
}
```
### Custom Error Types
```go
type ValidationError struct {
Field string
Value interface{}
Err error
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed for field %s with value %v: %v",
e.Field, e.Value, e.Err)
}
func (e *ValidationError) Unwrap() error {
return e.Err
}
// Usage
var validErr *ValidationError
if errors.As(err, &validErr) {
fmt.Printf("Field: %s\n", validErr.Field)
}
```
## Resource Management Patterns
### Defer for Cleanup
```go
func processFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// Process file
return nil
}
```
### Context for Cancellation
```go
func fetchData(ctx context.Context, url string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
```
### Sync.Pool for Object Reuse
```go
var bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func process() {
buf := bufferPool.Get().(*bytes.Buffer)
defer bufferPool.Put(buf)
buf.Reset()
// Use buffer
}
```
## Testing Patterns
### Table-Driven Tests
```go
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -1, -1, -2},
{"mixed signs", -5, 10, 5},
{"zeros", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d",
tt.a, tt.b, result, tt.expected)
}
})
}
}
```
### Mock Interfaces
```go
type Database interface {
Get(key string) (string, error)
Set(key, value string) error
}
type MockDB struct {
data map[string]string
}
func (m *MockDB) Get(key string) (string, error) {
val, ok := m.data[key]
if !ok {
return "", errors.New("not found")
}
return val, nil
}
func (m *MockDB) Set(key, value string) error {
m.data[key] = value
return nil
}
func TestUserService(t *testing.T) {
mockDB := &MockDB{data: make(map[string]string)}
service := NewUserService(mockDB)
// Test service
}
```
### Test Fixtures
```go
func setupTestDB(t *testing.T) (*sql.DB, func()) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatal(err)
}
// Setup schema
_, err = db.Exec(schema)
if err != nil {
t.Fatal(err)
}
cleanup := func() {
db.Close()
}
return db, cleanup
}
func TestDatabase(t *testing.T) {
db, cleanup := setupTestDB(t)
defer cleanup()
// Run tests
}
```

View File

@@ -0,0 +1,423 @@
# Effective Go - Key Points Summary
Source: https://go.dev/doc/effective_go
## Formatting
- Use `gofmt` to automatically format your code
- Indentation: use tabs
- Line length: no strict limit, but keep reasonable
- Parentheses: Go uses fewer parentheses than C/Java
## Commentary
- Every package should have a package comment
- Every exported name should have a doc comment
- Comments should be complete sentences
- Start comments with the name of the element being described
Example:
```go
// Package regexp implements regular expression search.
package regexp
// Compile parses a regular expression and returns, if successful,
// a Regexp object that can be used to match against text.
func Compile(str string) (*Regexp, error) {
```
## Names
### Package Names
- Short, concise, evocative
- Lowercase, single-word
- No underscores or mixedCaps
- Avoid stuttering (e.g., `bytes.Buffer` not `bytes.ByteBuffer`)
### Getters/Setters
- Getter: `Owner()` not `GetOwner()`
- Setter: `SetOwner()`
### Interface Names
- One-method interfaces use method name + -er suffix
- Examples: `Reader`, `Writer`, `Formatter`, `CloseNotifier`
### MixedCaps
- Use `MixedCaps` or `mixedCaps` rather than underscores
## Semicolons
- Lexer automatically inserts semicolons
- Never put opening brace on its own line
## Control Structures
### If
```go
if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}
```
### Redeclaration
```go
f, err := os.Open(name)
// err is declared here
d, err := f.Stat()
// err is redeclared here (same scope)
```
### For
```go
// Like a C for
for init; condition; post { }
// Like a C while
for condition { }
// Like a C for(;;)
for { }
// Range over array/slice/map/channel
for key, value := range oldMap {
newMap[key] = value
}
// If you only need the key
for key := range m {
// ...
}
// If you only need the value
for _, value := range array {
// ...
}
```
### Switch
- No automatic fall through
- Cases can be expressions
- Can switch on no value (acts like if-else chain)
```go
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
```
### Type Switch
```go
switch t := value.(type) {
case int:
fmt.Printf("int: %d\n", t)
case string:
fmt.Printf("string: %s\n", t)
default:
fmt.Printf("unexpected type %T\n", t)
}
```
## Functions
### Multiple Return Values
```go
func (file *File) Write(b []byte) (n int, err error) {
// ...
}
```
### Named Result Parameters
- Named results are initialized to zero values
- Can be used for documentation
- Enable naked returns
```go
func ReadFull(r Reader, buf []byte) (n int, err error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:]
}
return
}
```
### Defer
- Schedules function call to run after surrounding function returns
- LIFO order
- Arguments evaluated when defer executes
```go
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
```
## Data
### Allocation with new
- `new(T)` allocates zeroed storage for new item of type T
- Returns `*T`
- Returns memory address of newly allocated zero value
```go
p := new(int) // p is *int, points to zeroed int
```
### Constructors and Composite Literals
```go
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
return &File{fd: fd, name: name}
}
```
### Allocation with make
- `make(T, args)` creates slices, maps, and channels only
- Returns initialized (not zeroed) value of type T (not *T)
```go
make([]int, 10, 100) // slice: len=10, cap=100
make(map[string]int) // map
make(chan int, 10) // buffered channel
```
### Arrays
- Arrays are values, not pointers
- Passing array to function copies the entire array
- Array size is part of its type
### Slices
- Hold references to underlying array
- Can grow dynamically with `append`
- Passing slice passes reference
### Maps
- Hold references to underlying data structure
- Passing map passes reference
- Zero value is `nil`
### Printing
- `%v` - default format
- `%+v` - struct with field names
- `%#v` - Go syntax representation
- `%T` - type
- `%q` - quoted string
## Initialization
### Constants
- Created at compile time
- Can only be numbers, characters, strings, or booleans
### init Function
- Each source file can have `init()` function
- Called after package-level variables initialized
- Used for setup that can't be expressed as declarations
```go
func init() {
// initialization code
}
```
## Methods
### Pointers vs. Values
- Value methods can be invoked on pointers and values
- Pointer methods can only be invoked on pointers
Rule: Value methods can be called on both values and pointers, but pointer methods should only be called on pointers (though Go allows calling on addressable values).
```go
type ByteSlice []byte
func (slice ByteSlice) Append(data []byte) []byte {
// ...
}
func (p *ByteSlice) Append(data []byte) {
slice := *p
// ...
*p = slice
}
```
## Interfaces and Other Types
### Interfaces
- A type implements an interface by implementing its methods
- No explicit declaration of intent
### Type Assertions
```go
value, ok := str.(string)
```
### Type Switches
```go
switch v := value.(type) {
case string:
// v is string
case int:
// v is int
}
```
### Generality
- If a type exists only to implement an interface and will never have exported methods beyond that interface, there's no need to export the type itself
## The Blank Identifier
### Unused Imports and Variables
```go
import _ "net/http/pprof" // Import for side effects
```
### Interface Checks
```go
var _ json.Marshaler = (*RawMessage)(nil)
```
## Embedding
### Composition, not Inheritance
```go
type ReadWriter struct {
*Reader // *bufio.Reader
*Writer // *bufio.Writer
}
```
## Concurrency
### Share by Communicating
- Don't communicate by sharing memory; share memory by communicating
- Use channels to pass ownership
### Goroutines
- Cheap: small initial stack
- Multiplexed onto OS threads
- Prefix function call with `go` keyword
### Channels
- Allocate with `make`
- Unbuffered: synchronous
- Buffered: asynchronous up to buffer size
```go
ci := make(chan int) // unbuffered
cj := make(chan int, 0) // unbuffered
cs := make(chan *os.File, 100) // buffered
```
### Channels of Channels
```go
type Request struct {
args []int
f func([]int) int
resultChan chan int
}
```
### Parallelization
```go
const numCPU = runtime.NumCPU()
runtime.GOMAXPROCS(numCPU)
```
## Errors
### Error Type
```go
type error interface {
Error() string
}
```
### Custom Errors
```go
type PathError struct {
Op string
Path string
Err error
}
func (e *PathError) Error() string {
return e.Op + " " + e.Path + ": " + e.Err.Error()
}
```
### Panic
- Use for unrecoverable errors
- Generally avoid in library code
### Recover
- Called inside deferred function
- Stops panic sequence
- Returns value passed to panic
```go
func server(workChan <-chan *Work) {
for work := range workChan {
go safelyDo(work)
}
}
func safelyDo(work *Work) {
defer func() {
if err := recover(); err != nil {
log.Println("work failed:", err)
}
}()
do(work)
}
```
## A Web Server Example
```go
package main
import (
"fmt"
"log"
"net/http"
)
type Counter struct {
n int
}
func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
ctr.n++
fmt.Fprintf(w, "counter = %d\n", ctr.n)
}
func main() {
ctr := new(Counter)
http.Handle("/counter", ctr)
log.Fatal(http.ListenAndServe(":8080", nil))
}
```

View File

@@ -0,0 +1,528 @@
# Go Quick Reference Cheat Sheet
## Basic Syntax
### Hello World
```go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
```
### Variables
```go
var name string = "John"
var age int = 30
var height = 5.9 // type inference
// Short declaration (inside functions only)
count := 42
```
### Constants
```go
const Pi = 3.14159
const (
Sunday = iota // 0
Monday // 1
Tuesday // 2
)
```
## Data Types
### Basic Types
```go
bool // true, false
string // "hello"
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64
byte // alias for uint8
rune // alias for int32 (Unicode)
float32 float64
complex64 complex128
```
### Composite Types
```go
// Array (fixed size)
var arr [5]int
// Slice (dynamic)
slice := []int{1, 2, 3}
slice = append(slice, 4)
// Map
m := make(map[string]int)
m["key"] = 42
// Struct
type Person struct {
Name string
Age int
}
p := Person{Name: "Alice", Age: 30}
// Pointer
ptr := &p
```
## Functions
```go
// Basic function
func add(a, b int) int {
return a + b
}
// Named returns (preferred)
func divide(a, b float64) (result float64, err error) {
if b == 0 {
err = errors.New("division by zero")
return
}
result = a / b
return
}
// Variadic
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
// Multiple returns
func swap(a, b int) (int, int) {
return b, a
}
```
## Control Flow
### If/Else
```go
if x > 0 {
// positive
} else if x < 0 {
// negative
} else {
// zero
}
// With initialization
if err := doSomething(); err != nil {
return err
}
```
### For Loops
```go
// Traditional for
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// While-style
for condition {
}
// Infinite
for {
}
// Range
for i, v := range slice {
fmt.Printf("%d: %v\n", i, v)
}
for key, value := range myMap {
fmt.Printf("%s: %v\n", key, value)
}
```
### Switch
```go
switch x {
case 1:
fmt.Println("one")
case 2, 3:
fmt.Println("two or three")
default:
fmt.Println("other")
}
// Type switch
switch v := i.(type) {
case int:
fmt.Printf("int: %d\n", v)
case string:
fmt.Printf("string: %s\n", v)
}
```
## Methods & Interfaces
### Methods
```go
type Rectangle struct {
Width, Height float64
}
// Value receiver
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Pointer receiver
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
```
### Interfaces
```go
type Shape interface {
Area() float64
Perimeter() float64
}
// Empty interface (any type)
var x interface{} // or: var x any
```
## Concurrency
### Goroutines
```go
go doSomething()
go func() {
fmt.Println("In goroutine")
}()
```
### Channels
```go
// Create
ch := make(chan int) // unbuffered
ch := make(chan int, 10) // buffered
// Send & Receive
ch <- 42 // send
value := <-ch // receive
// Close
close(ch)
// Check if closed
value, ok := <-ch
```
### Select
```go
select {
case msg := <-ch1:
fmt.Println("ch1:", msg)
case msg := <-ch2:
fmt.Println("ch2:", msg)
case <-time.After(1 * time.Second):
fmt.Println("timeout")
default:
fmt.Println("no channel ready")
}
```
### Sync Package
```go
// Mutex
var mu sync.Mutex
mu.Lock()
defer mu.Unlock()
// RWMutex
var mu sync.RWMutex
mu.RLock()
defer mu.RUnlock()
// WaitGroup
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
// work
}()
wg.Wait()
```
## Error Handling
```go
// Create errors
err := errors.New("error message")
err := fmt.Errorf("failed: %w", originalErr)
// Check errors
if err != nil {
return err
}
// Custom error type
type MyError struct {
Msg string
}
func (e *MyError) Error() string {
return e.Msg
}
// Error checking (Go 1.13+)
if errors.Is(err, os.ErrNotExist) {
// handle
}
var pathErr *os.PathError
if errors.As(err, &pathErr) {
// handle
}
```
## Standard Library Snippets
### fmt - Formatting
```go
fmt.Print("text")
fmt.Println("text with newline")
fmt.Printf("Name: %s, Age: %d\n", name, age)
s := fmt.Sprintf("formatted %v", value)
```
### strings
```go
strings.Contains(s, substr)
strings.HasPrefix(s, prefix)
strings.Join([]string{"a", "b"}, ",")
strings.Split(s, ",")
strings.ToLower(s)
strings.TrimSpace(s)
```
### strconv
```go
i, _ := strconv.Atoi("42")
s := strconv.Itoa(42)
f, _ := strconv.ParseFloat("3.14", 64)
```
### io
```go
io.Copy(dst, src)
data, _ := io.ReadAll(r)
io.WriteString(w, "data")
```
### os
```go
file, _ := os.Open("file.txt")
defer file.Close()
os.Getenv("PATH")
os.Exit(1)
```
### net/http
```go
// Server
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
// Client
resp, _ := http.Get("https://example.com")
defer resp.Body.Close()
```
### encoding/json
```go
// Encode
data, _ := json.Marshal(obj)
// Decode
json.Unmarshal(data, &obj)
```
### time
```go
now := time.Now()
time.Sleep(5 * time.Second)
t.Format("2006-01-02 15:04:05")
time.Parse("2006-01-02", "2024-01-01")
```
## Testing
### Basic Test
```go
// mycode_test.go
package mypackage
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("got %d, want 5", result)
}
}
```
### Table-Driven Test
```go
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 2, 3, 5},
{"negative", -1, -1, -2},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("got %d, want %d", result, tt.expected)
}
})
}
}
```
### Benchmark
```go
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(2, 3)
}
}
```
## Go Commands
```bash
# Run
go run main.go
# Build
go build
go build -o myapp
# Test
go test
go test -v
go test -cover
go test -race
# Format
go fmt ./...
gofmt -s -w .
# Lint
go vet ./...
# Modules
go mod init module-name
go mod tidy
go get package@version
go get -u ./...
# Install
go install
# Documentation
go doc package.Function
```
## Common Patterns
### Defer
```go
file, err := os.Open("file.txt")
if err != nil {
return err
}
defer file.Close()
```
### Error Wrapping
```go
if err != nil {
return fmt.Errorf("failed to process: %w", err)
}
```
### Context
```go
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
```
### Options Pattern
```go
type Option func(*Config)
func WithPort(port int) Option {
return func(c *Config) {
c.port = port
}
}
func New(opts ...Option) *Server {
cfg := &Config{port: 8080}
for _, opt := range opts {
opt(cfg)
}
return &Server{cfg: cfg}
}
```
## Format Verbs
```go
%v // default format
%+v // struct with field names
%#v // Go-syntax representation
%T // type
%t // bool
%d // decimal integer
%b // binary
%o // octal
%x // hex (lowercase)
%X // hex (uppercase)
%f // float
%e // scientific notation
%s // string
%q // quoted string
%p // pointer address
%w // error wrapping
```
## Best Practices
1. Use `gofmt` to format code
2. Always check errors
3. Use named return values
4. Prefer composition over inheritance
5. Use defer for cleanup
6. Keep functions small and focused
7. Write table-driven tests
8. Document exported names
9. Use interfaces for flexibility
10. Follow Effective Go guidelines