mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-08 04:57:36 +00:00
shell: fish functions -> ~/.local/bin executables + bash/zsh ports; manage ~/.agents
- 16 cross-shell utilities converted to sh/bash chezmoi executables: ai c2p cp-appid extract_agents fab gdc gh-sonr-org-migrate ghg-clone ghn gho git-summary launch_omp_livediff_overlay lc-elir mdcp mdp pj (ghg-clone not named ghg: unrelated cargo binary owns that name) - cwd/history helpers stay per-shell: yy c cd clip-last + ghg/ghn/gho cd-wrappers in bash/functions/ and zsh/functions/, loaded by rc files - fish keeps only shell-state functions; converted ones now hit PATH - cp-appid ignore gating moved to .local/bin path - dot_agents/skills: 82 skills materialized from dotstate storage so dot_claude skill symlinks resolve on fresh bootstrap; dotstate profile/symlinks.json released .agents/skills .bashrc .zshrc
This commit is contained in:
1 parent
6776366ce6
commit
6406208b35
637 files changed
+100297
-497
No files matched your search
@@ -0,0 +1,442 @@
|
||||
# Generics and Type Parameters
|
||||
|
||||
## Basic Type Parameters
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
// Generic function with type parameter
|
||||
func Max[T constraints.Ordered](a, b T) T {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Multiple type parameters
|
||||
func Map[T, U any](slice []T, fn func(T) U) []U {
|
||||
result := make([]U, len(slice))
|
||||
for i, v := range slice {
|
||||
result[i] = fn(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Usage
|
||||
func main() {
|
||||
maxInt := Max(10, 20) // T = int
|
||||
maxFloat := Max(3.14, 2.71) // T = float64
|
||||
maxString := Max("abc", "xyz") // T = string
|
||||
|
||||
nums := []int{1, 2, 3}
|
||||
doubled := Map(nums, func(n int) int { return n * 2 })
|
||||
strings := Map(nums, func(n int) string { return fmt.Sprintf("%d", n) })
|
||||
}
|
||||
```
|
||||
|
||||
## Type Constraints
|
||||
|
||||
```go
|
||||
import "constraints"
|
||||
|
||||
// Built-in constraints
|
||||
type Number interface {
|
||||
constraints.Integer | constraints.Float
|
||||
}
|
||||
|
||||
func Sum[T Number](numbers []T) T {
|
||||
var total T
|
||||
for _, n := range numbers {
|
||||
total += n
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// Custom constraints with methods
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
func PrintAll[T Stringer](items []T) {
|
||||
for _, item := range items {
|
||||
fmt.Println(item.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Approximate constraint using ~
|
||||
type Integer interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
|
||||
type MyInt int
|
||||
|
||||
func Double[T Integer](n T) T {
|
||||
return n * 2
|
||||
}
|
||||
|
||||
// Works with both int and MyInt
|
||||
func main() {
|
||||
fmt.Println(Double(5)) // int
|
||||
fmt.Println(Double(MyInt(5))) // MyInt
|
||||
}
|
||||
```
|
||||
|
||||
## Generic Data Structures
|
||||
|
||||
```go
|
||||
// Generic Stack
|
||||
type Stack[T any] struct {
|
||||
items []T
|
||||
}
|
||||
|
||||
func NewStack[T any]() *Stack[T] {
|
||||
return &Stack[T]{
|
||||
items: make([]T, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Stack[T]) Push(item T) {
|
||||
s.items = append(s.items, item)
|
||||
}
|
||||
|
||||
func (s *Stack[T]) Pop() (T, bool) {
|
||||
if len(s.items) == 0 {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
item := s.items[len(s.items)-1]
|
||||
s.items = s.items[:len(s.items)-1]
|
||||
return item, true
|
||||
}
|
||||
|
||||
func (s *Stack[T]) IsEmpty() bool {
|
||||
return len(s.items) == 0
|
||||
}
|
||||
|
||||
// Usage
|
||||
intStack := NewStack[int]()
|
||||
intStack.Push(1)
|
||||
intStack.Push(2)
|
||||
|
||||
stringStack := NewStack[string]()
|
||||
stringStack.Push("hello")
|
||||
stringStack.Push("world")
|
||||
```
|
||||
|
||||
## Generic Map Operations
|
||||
|
||||
```go
|
||||
// Filter with generics
|
||||
func Filter[T any](slice []T, predicate func(T) bool) []T {
|
||||
result := make([]T, 0, len(slice))
|
||||
for _, v := range slice {
|
||||
if predicate(v) {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Reduce/Fold
|
||||
func Reduce[T, U any](slice []T, initial U, fn func(U, T) U) U {
|
||||
acc := initial
|
||||
for _, v := range slice {
|
||||
acc = fn(acc, v)
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
// Keys from map
|
||||
func Keys[K comparable, V any](m map[K]V) []K {
|
||||
keys := make([]K, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values from map
|
||||
func Values[K comparable, V any](m map[K]V) []V {
|
||||
values := make([]V, 0, len(m))
|
||||
for _, v := range m {
|
||||
values = append(values, v)
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// Usage
|
||||
numbers := []int{1, 2, 3, 4, 5, 6}
|
||||
evens := Filter(numbers, func(n int) bool { return n%2 == 0 })
|
||||
|
||||
sum := Reduce(numbers, 0, func(acc, n int) int { return acc + n })
|
||||
|
||||
m := map[string]int{"a": 1, "b": 2}
|
||||
keys := Keys(m) // []string{"a", "b"}
|
||||
values := Values(m) // []int{1, 2}
|
||||
```
|
||||
|
||||
## Generic Pairs and Tuples
|
||||
|
||||
```go
|
||||
// Generic Pair
|
||||
type Pair[T, U any] struct {
|
||||
First T
|
||||
Second U
|
||||
}
|
||||
|
||||
func NewPair[T, U any](first T, second U) Pair[T, U] {
|
||||
return Pair[T, U]{First: first, Second: second}
|
||||
}
|
||||
|
||||
func (p Pair[T, U]) Swap() Pair[U, T] {
|
||||
return Pair[U, T]{First: p.Second, Second: p.First}
|
||||
}
|
||||
|
||||
// Usage
|
||||
pair := NewPair("name", 42)
|
||||
swapped := pair.Swap() // Pair[int, string]
|
||||
|
||||
// Generic Result type (like Rust's Result<T, E>)
|
||||
type Result[T any] struct {
|
||||
value T
|
||||
err error
|
||||
}
|
||||
|
||||
func Ok[T any](value T) Result[T] {
|
||||
return Result[T]{value: value}
|
||||
}
|
||||
|
||||
func Err[T any](err error) Result[T] {
|
||||
return Result[T]{err: err}
|
||||
}
|
||||
|
||||
func (r Result[T]) IsOk() bool {
|
||||
return r.err == nil
|
||||
}
|
||||
|
||||
func (r Result[T]) Unwrap() (T, error) {
|
||||
return r.value, r.err
|
||||
}
|
||||
|
||||
func (r Result[T]) UnwrapOr(defaultValue T) T {
|
||||
if r.err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
return r.value
|
||||
}
|
||||
```
|
||||
|
||||
## Comparable Constraint
|
||||
|
||||
```go
|
||||
// Find using comparable
|
||||
func Find[T comparable](slice []T, target T) (int, bool) {
|
||||
for i, v := range slice {
|
||||
if v == target {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
// Contains
|
||||
func Contains[T comparable](slice []T, target T) bool {
|
||||
_, found := Find(slice, target)
|
||||
return found
|
||||
}
|
||||
|
||||
// Unique elements
|
||||
func Unique[T comparable](slice []T) []T {
|
||||
seen := make(map[T]struct{})
|
||||
result := make([]T, 0, len(slice))
|
||||
|
||||
for _, v := range slice {
|
||||
if _, exists := seen[v]; !exists {
|
||||
seen[v] = struct{}{}
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Usage
|
||||
nums := []int{1, 2, 2, 3, 3, 4}
|
||||
unique := Unique(nums) // []int{1, 2, 3, 4}
|
||||
|
||||
idx, found := Find([]string{"a", "b", "c"}, "b") // 1, true
|
||||
```
|
||||
|
||||
## Generic Interfaces
|
||||
|
||||
```go
|
||||
// Generic interface
|
||||
type Container[T any] interface {
|
||||
Add(item T)
|
||||
Remove() (T, bool)
|
||||
Size() int
|
||||
}
|
||||
|
||||
// Implementation
|
||||
type Queue[T any] struct {
|
||||
items []T
|
||||
}
|
||||
|
||||
func (q *Queue[T]) Add(item T) {
|
||||
q.items = append(q.items, item)
|
||||
}
|
||||
|
||||
func (q *Queue[T]) Remove() (T, bool) {
|
||||
if len(q.items) == 0 {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
item := q.items[0]
|
||||
q.items = q.items[1:]
|
||||
return item, true
|
||||
}
|
||||
|
||||
func (q *Queue[T]) Size() int {
|
||||
return len(q.items)
|
||||
}
|
||||
|
||||
// Function accepting generic interface
|
||||
func ProcessContainer[T any](c Container[T], item T) {
|
||||
c.Add(item)
|
||||
fmt.Printf("Container size: %d\n", c.Size())
|
||||
}
|
||||
```
|
||||
|
||||
## Type Inference
|
||||
|
||||
```go
|
||||
// Type inference works in most cases
|
||||
func Identity[T any](x T) T {
|
||||
return x
|
||||
}
|
||||
|
||||
// No need to specify type
|
||||
result := Identity(42) // T inferred as int
|
||||
str := Identity("hello") // T inferred as string
|
||||
|
||||
// Type inference with constraints
|
||||
func Min[T constraints.Ordered](a, b T) T {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Inferred from arguments
|
||||
minVal := Min(10, 20) // T = int
|
||||
minFloat := Min(1.5, 2.5) // T = float64
|
||||
|
||||
// Explicit type when needed
|
||||
result := Map[int, string]([]int{1, 2}, func(n int) string {
|
||||
return fmt.Sprintf("%d", n)
|
||||
})
|
||||
```
|
||||
|
||||
## Generic Channels
|
||||
|
||||
```go
|
||||
// Generic channel operations
|
||||
func Merge[T any](channels ...<-chan T) <-chan T {
|
||||
out := make(chan T)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for _, ch := range channels {
|
||||
wg.Add(1)
|
||||
go func(c <-chan T) {
|
||||
defer wg.Done()
|
||||
for v := range c {
|
||||
out <- v
|
||||
}
|
||||
}(ch)
|
||||
}
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(out)
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Generic pipeline stage
|
||||
func Stage[T, U any](in <-chan T, fn func(T) U) <-chan U {
|
||||
out := make(chan U)
|
||||
go func() {
|
||||
defer close(out)
|
||||
for v := range in {
|
||||
out <- fn(v)
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
// Usage
|
||||
ch1 := make(chan int)
|
||||
ch2 := make(chan int)
|
||||
|
||||
merged := Merge(ch1, ch2)
|
||||
|
||||
numbers := make(chan int)
|
||||
doubled := Stage(numbers, func(n int) int { return n * 2 })
|
||||
strings := Stage(doubled, func(n int) string { return fmt.Sprintf("%d", n) })
|
||||
```
|
||||
|
||||
## Union Constraints
|
||||
|
||||
```go
|
||||
// Union of types
|
||||
type StringOrInt interface {
|
||||
string | int
|
||||
}
|
||||
|
||||
func Process[T StringOrInt](val T) string {
|
||||
return fmt.Sprintf("%v", val)
|
||||
}
|
||||
|
||||
// More complex unions
|
||||
type Numeric interface {
|
||||
int | int8 | int16 | int32 | int64 |
|
||||
uint | uint8 | uint16 | uint32 | uint64 |
|
||||
float32 | float64
|
||||
}
|
||||
|
||||
func Abs[T Numeric](n T) T {
|
||||
if n < 0 {
|
||||
return -n
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Union with methods
|
||||
type Serializable interface {
|
||||
string | []byte
|
||||
}
|
||||
|
||||
func Serialize[T Serializable](data T) []byte {
|
||||
switch v := any(data).(type) {
|
||||
case string:
|
||||
return []byte(v)
|
||||
case []byte:
|
||||
return v
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Feature | Syntax | Use Case |
|
||||
|---------|--------|----------|
|
||||
| Basic generic | `func F[T any]()` | Any type |
|
||||
| Constraint | `func F[T Constraint]()` | Restricted types |
|
||||
| Multiple params | `func F[T, U any]()` | Multiple type variables |
|
||||
| Comparable | `func F[T comparable]()` | Types supporting == and != |
|
||||
| Ordered | `func F[T constraints.Ordered]()` | Types supporting <, >, <=, >= |
|
||||
| Union | `T interface{int \| string}` | Either type |
|
||||
| Approximate | `~int` | Include type aliases |
|
||||
Reference in new issue
Block a user