Skip to content

Instantly share code, notes, and snippets.

@up1
Last active August 29, 2026 09:01
Show Gist options
  • Select an option

  • Save up1/47702cfcfcde2ea3336adce125629904 to your computer and use it in GitHub Desktop.

Select an option

Save up1/47702cfcfcde2ea3336adce125629904 to your computer and use it in GitHub Desktop.
$go-modern-guidelines
go-modern-guidelines provides modern Go coding guidelines for AI agents, so they can write up-to-date Go code despite their knowledge cutoff.
Commands:
list [--go-version <version> | --file-path <path> | <path>]
Return short modern Go coding guidelines supported by the resolved Go version,
ordered newest first.
explain [--guideline-id <id>]... <id>...
Return detailed guidance and before/after examples for specific guideline ids.
$go-modern-guidelines list --go-version 1.24
$go-modern-guidelines list
generic_methods: Use generic methods instead of package-level generic helper functions when the operation naturally belongs to the type itself.
json_v2: Use encoding/json/v2 for new JSON code in Go 1.27+; leave existing encoding/json code unchanged unless migration is explicitly requested.
promoted_field_literals: Set embedded struct fields directly with promoted field names in Go 1.27+ struct literals instead of constructing the embedded struct explicitly.
strings_bytes_cut_last: Use strings.CutLast and bytes.CutLast instead of LastIndex plus manual slicing around the last separator.
stdlib_uuid: Use the standard library uuid package instead of third-party libraries or custom UUID implementations when targeting Go 1.27+.
url_clone: Use net/url URL.Clone and Values.Clone methods to copy URLs and URL values instead of manual copying.
new_expression: Use new(value) for pointer fields or arguments instead of generic/type-specific pointer helper functions or temporary variables used only for &value.
errors_as_type: Use errors.AsType[T](err) when checking whether an error matches a specific type.
sync_waitgroup_go: Use wg.Go when spawning goroutines tracked by a sync.WaitGroup.
testing_t_context: Use t.Context() when a test function needs a context tied to the test lifetime.
json_omitzero: Use omitzero on JSON-tagged bool, numeric, struct, and time fields whose zero value should be omitted; keep omitempty for empty strings, slices, and maps.
testing_b_loop: Use b.Loop() for the main loop in benchmark functions.
strings_split_seq: Use strings or bytes SplitSeq and FieldsSeq helpers when iterating over split results.
maps_keys_values_iter: Use maps.Keys or maps.Values directly as iterators instead of manually looping over a map.
slices_collect: Use slices.Collect to build a slice from an iterator.
slices_sorted: Use slices.Sorted to collect and sort iterator values in one step.
time_tick_gc: Use time.Tick when it fits; Go 1.23 can recover unreferenced tickers without requiring Stop for GC.
range_over_int: Use for i := range n when iterating from 0 to n-1.
loopvar_capture: Do not add redundant loop-variable copies before closures or taking addresses; Go 1.22 gives each iteration its own variables.
cmp_or: Use cmp.Or to pick the first non-zero value from a fallback chain.
reflect_type_for: Use reflect.TypeFor[T]() instead of reflect.TypeOf((*T)(nil)).Elem().
http_servemux_patterns: Use method-aware ServeMux patterns and r.PathValue for path parameters.
min_max: Use built-in min and max instead of handwritten comparisons.
clear: Use clear(m) to delete all map entries or clear(s) to zero slice elements.
slices_contains: Use slices.Contains instead of a manual search loop.
slices_index: Use slices.Index to find the index of an element, returning -1 when absent.
slices_index_func: Use slices.IndexFunc to find an element by predicate.
slices_sort_func: Use slices.SortFunc with cmp.Compare instead of sort.Slice for typed comparisons.
slices_sort: Use slices.Sort for slices of ordered values.
slices_max_min: Use slices.Max and slices.Min instead of manual loops over ordered values.
slices_reverse: Use slices.Reverse instead of a manual swap loop.
slices_compact: Use slices.Compact to remove consecutive duplicates in place.
slices_clip: Use slices.Clip to remove unused capacity.
slices_clone: Use slices.Clone to copy a slice.
maps_clone: Use maps.Clone instead of manual map iteration.
maps_copy: Use maps.Copy to copy entries from one map into another.
maps_delete_func: Use maps.DeleteFunc to delete map entries that match a predicate.
sync_once_func: Use sync.OnceFunc instead of sync.Once plus a wrapper closure.
sync_once_value: Use sync.OnceValue to memoize a computed value.
context_after_func: Use context.AfterFunc to run cleanup when a context is canceled.
context_timeout_deadline_cause: Use timeout and deadline contexts with causes when callers need to inspect the cancellation reason.
strings_clone: Use strings.Clone to copy a string without retaining shared backing memory.
bytes_clone: Use bytes.Clone to copy a byte slice.
strings_cut_prefix_suffix: Use strings.CutPrefix or strings.CutSuffix when you need both the trimmed result and whether it matched.
errors_join: Use errors.Join to combine multiple errors while preserving error matching.
context_cancel_cause: Use context.WithCancelCause and context.Cause when cancellation needs to carry an error cause.
fmt_appendf: Use fmt.Appendf when appending formatted text to a byte slice and an intermediate fmt.Sprintf string is unnecessary.
atomic_types: Use typed atomics such as atomic.Bool, atomic.Int64, and atomic.Pointer[T] instead of untyped atomic functions.
any: Use any instead of interface{}.
bytes_cut: Use bytes.Cut instead of bytes.Index plus manual slicing.
strings_cut: Use strings.Cut instead of strings.Index plus manual slicing.
errors_is: Use errors.Is(err, target) instead of err == target so wrapped errors are handled correctly.
time_until: Use time.Until(deadline) instead of deadline.Sub(time.Now()).
time_since: Use time.Since(start) instead of time.Now().Sub(start).
$go-modern-guidelines explain generic_methods
generic_methods:
Since: Go 1.27
Summary:
Use generic methods instead of package-level generic helper functions when the operation naturally belongs to the type itself.
Details:
Generic methods keep operations in the namespace of the type that owns them. Keep package-level helpers for operations that do not naturally belong to one receiver type.
Examples:
Before:
type Set[T comparable] map[T]struct{}
func Map[T comparable, U any](s Set[T], f func(T) U) []U {
out := make([]U, 0, len(s))
for value := range s {
out = append(out, f(value))
}
return out
}
names := Map(users, func(user User) string {
return user.Name
})
After:
type Set[T comparable] map[T]struct{}
func (s Set[T]) Map[U any](f func(T) U) []U {
out := make([]U, 0, len(s))
for value := range s {
out = append(out, f(value))
}
return out
}
names := users.Map(func(user User) string {
return user.Name
})
# ติดตั้ง
$go install golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest
go: downloading golang.org/x/tools v0.49.0
go: downloading golang.org/x/mod v0.39.0
$modernize
modernize is a tool for static analysis of Go programs.
Usage: modernize [-flag] [package]
Run 'modernize help' for more detail,
or 'modernize help name' for details and flags of a specific analyzer.
# Fix code
$modernize -fix main.go
package main
func main() {
for i := 0; i < 10; i++ {
}
}
package main
func main() {
// Before
for i := 0; i < 10; i++ {
}
// After
// replaced the empty three-clause loop with for i := range 10 (range-over-int, Go 1.22+)
for range 10 {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment