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:
423
.claude/skills/golang/references/effective-go-summary.md
Normal file
423
.claude/skills/golang/references/effective-go-summary.md
Normal 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))
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user