any is an alias for interface{} — the empty interface with no methods. Every type satisfies it. It is Go's escape hatch for "I genuinely don't know the type at compile time."
any vs Java Object
☕ Java — Object as universal base
Object val = 42; // autoboxed to Integerval = "now a string";// Cast to use itif (val instanceof String s) { System.out.println(s.toUpperCase());}// Old styleString s = (String) val; // ClassCastException if wrong
◎ Go — any (interface{}) as universal type
var val any = 42val = "now a string" // reassign to different type — fine// Type assertion — explicit checks, ok := val.(string) // ok = true if val is a stringif ok { fmt.Println(strings.ToUpper(s))}// Type assertion without check — panics if wrong types2 := val.(string) // panics if val is not a string
Why Go does thisGo does not have an object hierarchy — there is no universal base class. any is simply an interface with no method requirements. No autoboxing, no class cast exceptions — just an explicit assertion that you check.
Type switch — clean multi-type handling
type switch — the idiomatic way to handle any
func describe(val any) string { // switch v := val.(type) extracts the value as the correct type // v has the concrete type in each case branch switch v := val.(type) { case string: return "string: " + v // v is string here case int: return fmt.Sprintf("int: %d", v) // v is int here case bool: return fmt.Sprintf("bool: %t", v) case []byte: return fmt.Sprintf("bytes: %d bytes", len(v)) default: return fmt.Sprintf("unknown type: %T", v) // %T prints the concrete type name }}
Where you see any in a comms engine
metadata maps and gin.H
// Message metadata bag — different messages carry different metadatatype Message struct { ID int64 Topic string Payload []byte Metadata map[string]any // open-ended key-value bag}// Store any type of metadatamsg.Metadata = map[string]any{}msg.Metadata["trace_id"] = "abc-123-def"msg.Metadata["priority"] = 5msg.Metadata["retryable"] = true// Retrieve and asserttraceID, ok := msg.Metadata["trace_id"].(string)priority, ok := msg.Metadata["priority"].(int)// gin.H is literally just: type H map[string]any// so when you write gin.H{...} you are writing map[string]any{...}c.JSON(200, gin.H{"status": "ok", "count": 42})
!Avoid any in hot paths. Type assertions have a small runtime cost and you lose compile-time safety. Prefer typed interfaces or generics (section 15) when possible.