[{"data":1,"prerenderedAt":3273},["ShallowReactive",2],{"page-\u002Fgo\u002F12-interfaces":3},{"id":4,"title":5,"body":6,"description":3266,"extension":3267,"meta":3268,"navigation":110,"path":3269,"seo":3270,"stem":3271,"__hash__":3272},"content\u002Fgo\u002F12-interfaces.md","12 — Interfaces",{"type":7,"value":8,"toc":3260},"minimark",[9,13,18,3107,3243,3247,3256],[10,11,5],"h1",{"id":12},"_12-interfaces",[14,15,17],"h2",{"id":16},"interface-internals-the-type-value-pair","Interface Internals — The (Type, Value) Pair",[19,20,22,297,305],"code-wrapper",{"language":21},"go",[23,24,28],"pre",{"className":25,"code":26,"language":21,"meta":27,"style":27},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F An interface value is a 2-word header:\n\u002F\u002F   ┌──────────┬──────────┐\n\u002F\u002F   │ type     │ value    │\n\u002F\u002F   │ 8 bytes  │ 8 bytes  │\n\u002F\u002F   └──────────┴──────────┘\n\u002F\u002F\n\u002F\u002F type:  pointer to the interface's dynamic type metadata (itable)\n\u002F\u002F value: pointer to the concrete data (or the data itself if ≤ 1 word)\n\u002F\u002F\n\u002F\u002F The itable maps the interface's methods to the concrete type's methods.\n\u002F\u002F Method dispatch goes: interface method → itable → concrete method.\n\u002F\u002F This is a single indirection — fast, but not as fast as a direct call.\n\ntype Speaker interface{ Speak() string }\n\ntype Dog struct{ Name string }\nfunc (d Dog) Speak() string { return d.Name + \" barks\" }\n\nfunc internals() {\n    var s Speaker\n    s = Dog{Name: \"Rex\"}  \u002F\u002F s holds (Dog, Dog{Name: \"Rex\"})\n    \u002F\u002F type = Dog, value = Dog{Name: \"Rex\"} (stored inline if ≤ 1 word,\n    \u002F\u002F   or a pointer to heap if larger)\n    fmt.Println(s.Speak())  \u002F\u002F dispatches via itable → Dog.Speak\n}\n","",[29,30,31,40,46,52,58,64,70,76,82,87,93,99,105,112,142,147,165,208,213,224,236,259,265,271,291],"code",{"__ignoreMap":27},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sdCPZ","\u002F\u002F An interface value is a 2-word header:\n",[32,41,43],{"class":34,"line":42},2,[32,44,45],{"class":38},"\u002F\u002F   ┌──────────┬──────────┐\n",[32,47,49],{"class":34,"line":48},3,[32,50,51],{"class":38},"\u002F\u002F   │ type     │ value    │\n",[32,53,55],{"class":34,"line":54},4,[32,56,57],{"class":38},"\u002F\u002F   │ 8 bytes  │ 8 bytes  │\n",[32,59,61],{"class":34,"line":60},5,[32,62,63],{"class":38},"\u002F\u002F   └──────────┴──────────┘\n",[32,65,67],{"class":34,"line":66},6,[32,68,69],{"class":38},"\u002F\u002F\n",[32,71,73],{"class":34,"line":72},7,[32,74,75],{"class":38},"\u002F\u002F type:  pointer to the interface's dynamic type metadata (itable)\n",[32,77,79],{"class":34,"line":78},8,[32,80,81],{"class":38},"\u002F\u002F value: pointer to the concrete data (or the data itself if ≤ 1 word)\n",[32,83,85],{"class":34,"line":84},9,[32,86,69],{"class":38},[32,88,90],{"class":34,"line":89},10,[32,91,92],{"class":38},"\u002F\u002F The itable maps the interface's methods to the concrete type's methods.\n",[32,94,96],{"class":34,"line":95},11,[32,97,98],{"class":38},"\u002F\u002F Method dispatch goes: interface method → itable → concrete method.\n",[32,100,102],{"class":34,"line":101},12,[32,103,104],{"class":38},"\u002F\u002F This is a single indirection — fast, but not as fast as a direct call.\n",[32,106,108],{"class":34,"line":107},13,[32,109,111],{"emptyLinePlaceholder":110},true,"\n",[32,113,115,119,123,126,130,133,136,139],{"class":34,"line":114},14,[32,116,118],{"class":117},"svdQ7","type",[32,120,122],{"class":121},"sIsaT"," Speaker",[32,124,125],{"class":117}," interface",[32,127,129],{"class":128},"ssxIu","{ ",[32,131,132],{"class":121},"Speak",[32,134,135],{"class":128},"() ",[32,137,138],{"class":117},"string",[32,140,141],{"class":128}," }\n",[32,143,145],{"class":34,"line":144},15,[32,146,111],{"emptyLinePlaceholder":110},[32,148,150,152,155,158,161,163],{"class":34,"line":149},16,[32,151,118],{"class":117},[32,153,154],{"class":121}," Dog",[32,156,157],{"class":117}," struct",[32,159,160],{"class":128},"{ Name ",[32,162,138],{"class":117},[32,164,141],{"class":128},[32,166,168,171,174,178,181,184,186,188,190,193,196,199,202,206],{"class":34,"line":167},17,[32,169,170],{"class":117},"func",[32,172,173],{"class":128}," (",[32,175,177],{"class":176},"sCrzJ","d ",[32,179,180],{"class":121},"Dog",[32,182,183],{"class":128},") ",[32,185,132],{"class":121},[32,187,135],{"class":128},[32,189,138],{"class":117},[32,191,192],{"class":128}," { ",[32,194,195],{"class":117},"return",[32,197,198],{"class":128}," d.Name ",[32,200,201],{"class":117},"+",[32,203,205],{"class":204},"sJ6F3"," \" barks\"",[32,207,141],{"class":128},[32,209,211],{"class":34,"line":210},18,[32,212,111],{"emptyLinePlaceholder":110},[32,214,216,218,221],{"class":34,"line":215},19,[32,217,170],{"class":117},[32,219,220],{"class":121}," internals",[32,222,223],{"class":128},"() {\n",[32,225,227,230,233],{"class":34,"line":226},20,[32,228,229],{"class":117},"    var",[32,231,232],{"class":128}," s ",[32,234,235],{"class":121},"Speaker\n",[32,237,239,242,245,247,250,253,256],{"class":34,"line":238},21,[32,240,241],{"class":128},"    s ",[32,243,244],{"class":117},"=",[32,246,154],{"class":121},[32,248,249],{"class":128},"{Name: ",[32,251,252],{"class":204},"\"Rex\"",[32,254,255],{"class":128},"}  ",[32,257,258],{"class":38},"\u002F\u002F s holds (Dog, Dog{Name: \"Rex\"})\n",[32,260,262],{"class":34,"line":261},22,[32,263,264],{"class":38},"    \u002F\u002F type = Dog, value = Dog{Name: \"Rex\"} (stored inline if ≤ 1 word,\n",[32,266,268],{"class":34,"line":267},23,[32,269,270],{"class":38},"    \u002F\u002F   or a pointer to heap if larger)\n",[32,272,274,277,280,283,285,288],{"class":34,"line":273},24,[32,275,276],{"class":128},"    fmt.",[32,278,279],{"class":121},"Println",[32,281,282],{"class":128},"(s.",[32,284,132],{"class":121},[32,286,287],{"class":128},"())  ",[32,289,290],{"class":38},"\u002F\u002F dispatches via itable → Dog.Speak\n",[32,292,294],{"class":34,"line":293},25,[32,295,296],{"class":128},"}\n",[14,298,300,301,304],{"id":299},"implicit-satisfaction-no-implements-keyword","Implicit Satisfaction — No ",[29,302,303],{},"implements"," Keyword",[19,306,307,524,528],{"language":21},[23,308,310],{"className":25,"code":309,"language":21,"meta":27,"style":27},"\u002F\u002F Go interfaces are satisfied IMPLICITLY — the type doesn't declare\n\u002F\u002F \"I implement Speaker.\" The compiler checks that all methods exist.\n\u002F\u002F\n\u002F\u002F This enables:\n\u002F\u002F   1. Decoupling: a type can satisfy an interface defined elsewhere\n\u002F\u002F   2. Retroactive: define an interface AFTER types exist\n\u002F\u002F   3. No import cycles: the interface and the type don't need to know\n\u002F\u002F      about each other\n\n\u002F\u002F Define the interface (consumer-side):\ntype Stringer interface {\n    String() string\n}\n\n\u002F\u002F A type defined elsewhere satisfies it automatically:\ntype Celsius float64\nfunc (c Celsius) String() string { return fmt.Sprintf(\"%.1f°C\", c) }\n\n\u002F\u002F Celsius satisfies Stringer — no declaration of intent needed.\n\u002F\u002F You can even define an interface for a type in the STD LIBRARY:\n\u002F\u002F   type ReadCloser interface { io.Reader; io.Close() }\n\u002F\u002F   — satisfied by *os.File, *bufio.Reader (if it has Close), etc.\n\n\u002F\u002F ─── Compile-time check (the idiom) ───\nvar _ Stringer = Celsius(0)  \u002F\u002F compile error if Celsius doesn't satisfy Stringer\n\u002F\u002F This asserts satisfaction at compile time — catches breakage when a\n\u002F\u002F method is removed or the interface changes. Common in library code.\n",[29,311,312,317,322,326,331,336,341,346,351,355,360,372,382,386,390,395,405,452,456,461,466,471,476,480,485,512,518],{"__ignoreMap":27},[32,313,314],{"class":34,"line":35},[32,315,316],{"class":38},"\u002F\u002F Go interfaces are satisfied IMPLICITLY — the type doesn't declare\n",[32,318,319],{"class":34,"line":42},[32,320,321],{"class":38},"\u002F\u002F \"I implement Speaker.\" The compiler checks that all methods exist.\n",[32,323,324],{"class":34,"line":48},[32,325,69],{"class":38},[32,327,328],{"class":34,"line":54},[32,329,330],{"class":38},"\u002F\u002F This enables:\n",[32,332,333],{"class":34,"line":60},[32,334,335],{"class":38},"\u002F\u002F   1. Decoupling: a type can satisfy an interface defined elsewhere\n",[32,337,338],{"class":34,"line":66},[32,339,340],{"class":38},"\u002F\u002F   2. Retroactive: define an interface AFTER types exist\n",[32,342,343],{"class":34,"line":72},[32,344,345],{"class":38},"\u002F\u002F   3. No import cycles: the interface and the type don't need to know\n",[32,347,348],{"class":34,"line":78},[32,349,350],{"class":38},"\u002F\u002F      about each other\n",[32,352,353],{"class":34,"line":84},[32,354,111],{"emptyLinePlaceholder":110},[32,356,357],{"class":34,"line":89},[32,358,359],{"class":38},"\u002F\u002F Define the interface (consumer-side):\n",[32,361,362,364,367,369],{"class":34,"line":95},[32,363,118],{"class":117},[32,365,366],{"class":121}," Stringer",[32,368,125],{"class":117},[32,370,371],{"class":128}," {\n",[32,373,374,377,379],{"class":34,"line":101},[32,375,376],{"class":121},"    String",[32,378,135],{"class":128},[32,380,381],{"class":117},"string\n",[32,383,384],{"class":34,"line":107},[32,385,296],{"class":128},[32,387,388],{"class":34,"line":114},[32,389,111],{"emptyLinePlaceholder":110},[32,391,392],{"class":34,"line":144},[32,393,394],{"class":38},"\u002F\u002F A type defined elsewhere satisfies it automatically:\n",[32,396,397,399,402],{"class":34,"line":149},[32,398,118],{"class":117},[32,400,401],{"class":121}," Celsius",[32,403,404],{"class":117}," float64\n",[32,406,407,409,411,414,417,419,422,424,426,428,430,433,436,439,442,446,449],{"class":34,"line":167},[32,408,170],{"class":117},[32,410,173],{"class":128},[32,412,413],{"class":176},"c ",[32,415,416],{"class":121},"Celsius",[32,418,183],{"class":128},[32,420,421],{"class":121},"String",[32,423,135],{"class":128},[32,425,138],{"class":117},[32,427,192],{"class":128},[32,429,195],{"class":117},[32,431,432],{"class":128}," fmt.",[32,434,435],{"class":121},"Sprintf",[32,437,438],{"class":128},"(",[32,440,441],{"class":204},"\"",[32,443,445],{"class":444},"snvgF","%.1f",[32,447,448],{"class":204},"°C\"",[32,450,451],{"class":128},", c) }\n",[32,453,454],{"class":34,"line":210},[32,455,111],{"emptyLinePlaceholder":110},[32,457,458],{"class":34,"line":215},[32,459,460],{"class":38},"\u002F\u002F Celsius satisfies Stringer — no declaration of intent needed.\n",[32,462,463],{"class":34,"line":226},[32,464,465],{"class":38},"\u002F\u002F You can even define an interface for a type in the STD LIBRARY:\n",[32,467,468],{"class":34,"line":238},[32,469,470],{"class":38},"\u002F\u002F   type ReadCloser interface { io.Reader; io.Close() }\n",[32,472,473],{"class":34,"line":261},[32,474,475],{"class":38},"\u002F\u002F   — satisfied by *os.File, *bufio.Reader (if it has Close), etc.\n",[32,477,478],{"class":34,"line":267},[32,479,111],{"emptyLinePlaceholder":110},[32,481,482],{"class":34,"line":273},[32,483,484],{"class":38},"\u002F\u002F ─── Compile-time check (the idiom) ───\n",[32,486,487,490,493,496,499,501,503,506,509],{"class":34,"line":293},[32,488,489],{"class":117},"var",[32,491,492],{"class":128}," _ ",[32,494,495],{"class":121},"Stringer",[32,497,498],{"class":117}," =",[32,500,401],{"class":121},[32,502,438],{"class":128},[32,504,505],{"class":444},"0",[32,507,508],{"class":128},")  ",[32,510,511],{"class":38},"\u002F\u002F compile error if Celsius doesn't satisfy Stringer\n",[32,513,515],{"class":34,"line":514},26,[32,516,517],{"class":38},"\u002F\u002F This asserts satisfaction at compile time — catches breakage when a\n",[32,519,521],{"class":34,"line":520},27,[32,522,523],{"class":38},"\u002F\u002F method is removed or the interface changes. Common in library code.\n",[14,525,527],{"id":526},"the-nil-interface-trap-the-1-go-gotcha","The Nil Interface Trap — The #1 Go Gotcha",[19,529,530,917,921],{"language":21},[23,531,533],{"className":25,"code":532,"language":21,"meta":27,"style":27},"\u002F\u002F An interface is nil ONLY when BOTH type and value are nil.\n\u002F\u002F Wrapping a nil pointer in an interface makes the interface NON-NIL.\n\ntype Logger interface{ Log(string) }\n\ntype nullLogger struct{}\nfunc (n *nullLogger) Log(string) {}\n\nfunc getLogger(enabled bool) Logger {\n    var l *nullLogger = nil  \u002F\u002F nil pointer\n    if enabled {\n        l = &nullLogger{}\n    }\n    return l  \u002F\u002F ❌ returns (type=*nullLogger, value=nil) — NON-NIL interface!\n}\n\nfunc nilTrap() {\n    l := getLogger(false)\n    fmt.Println(l == nil)  \u002F\u002F false! The interface has a type, so it's non-nil.\n    \u002F\u002F l.Log(\"hello\")      \u002F\u002F panics: nil pointer dereference (the value is nil)\n}\n\n\u002F\u002F ✅ CORRECT: return nil directly for a nil interface:\nfunc getLoggerFixed(enabled bool) Logger {\n    if !enabled {\n        return nil  \u002F\u002F returns a true nil interface (type=nil, value=nil)\n    }\n    return &nullLogger{}\n}\n\nfunc fixedDemo() {\n    l := getLoggerFixed(false)\n    fmt.Println(l == nil)  \u002F\u002F true\n}\n\n\u002F\u002F ┌──────────────────────────────────────────────────────────────────────┐\n\u002F\u002F │ nil interface    │ (type=nil, value=nil) │ == nil → true             │\n\u002F\u002F │ non-nil wrapping │ (type=*T,  value=nil) │ == nil → FALSE (the trap) │\n\u002F\u002F │ Calling a method │ panics (nil pointer dereference)                  │\n\u002F\u002F └──────────────────────────────────────────────────────────────────────┘\n",[29,534,535,540,545,549,570,574,586,612,616,638,657,665,679,684,695,699,703,712,730,749,757,761,765,770,789,799,809,813,824,829,834,844,859,877,882,887,893,899,905,911],{"__ignoreMap":27},[32,536,537],{"class":34,"line":35},[32,538,539],{"class":38},"\u002F\u002F An interface is nil ONLY when BOTH type and value are nil.\n",[32,541,542],{"class":34,"line":42},[32,543,544],{"class":38},"\u002F\u002F Wrapping a nil pointer in an interface makes the interface NON-NIL.\n",[32,546,547],{"class":34,"line":48},[32,548,111],{"emptyLinePlaceholder":110},[32,550,551,553,556,558,560,563,565,567],{"class":34,"line":54},[32,552,118],{"class":117},[32,554,555],{"class":121}," Logger",[32,557,125],{"class":117},[32,559,129],{"class":128},[32,561,562],{"class":121},"Log",[32,564,438],{"class":128},[32,566,138],{"class":117},[32,568,569],{"class":128},") }\n",[32,571,572],{"class":34,"line":60},[32,573,111],{"emptyLinePlaceholder":110},[32,575,576,578,581,583],{"class":34,"line":66},[32,577,118],{"class":117},[32,579,580],{"class":121}," nullLogger",[32,582,157],{"class":117},[32,584,585],{"class":128},"{}\n",[32,587,588,590,592,595,598,601,603,605,607,609],{"class":34,"line":72},[32,589,170],{"class":117},[32,591,173],{"class":128},[32,593,594],{"class":176},"n ",[32,596,597],{"class":117},"*",[32,599,600],{"class":121},"nullLogger",[32,602,183],{"class":128},[32,604,562],{"class":121},[32,606,438],{"class":128},[32,608,138],{"class":117},[32,610,611],{"class":128},") {}\n",[32,613,614],{"class":34,"line":78},[32,615,111],{"emptyLinePlaceholder":110},[32,617,618,620,623,625,628,631,633,636],{"class":34,"line":84},[32,619,170],{"class":117},[32,621,622],{"class":121}," getLogger",[32,624,438],{"class":128},[32,626,627],{"class":176},"enabled",[32,629,630],{"class":117}," bool",[32,632,183],{"class":128},[32,634,635],{"class":121},"Logger",[32,637,371],{"class":128},[32,639,640,642,645,647,649,651,654],{"class":34,"line":89},[32,641,229],{"class":117},[32,643,644],{"class":128}," l ",[32,646,597],{"class":117},[32,648,600],{"class":121},[32,650,498],{"class":117},[32,652,653],{"class":444}," nil",[32,655,656],{"class":38},"  \u002F\u002F nil pointer\n",[32,658,659,662],{"class":34,"line":95},[32,660,661],{"class":117},"    if",[32,663,664],{"class":128}," enabled {\n",[32,666,667,670,672,675,677],{"class":34,"line":101},[32,668,669],{"class":128},"        l ",[32,671,244],{"class":117},[32,673,674],{"class":117}," &",[32,676,600],{"class":121},[32,678,585],{"class":128},[32,680,681],{"class":34,"line":107},[32,682,683],{"class":128},"    }\n",[32,685,686,689,692],{"class":34,"line":114},[32,687,688],{"class":117},"    return",[32,690,691],{"class":128}," l  ",[32,693,694],{"class":38},"\u002F\u002F ❌ returns (type=*nullLogger, value=nil) — NON-NIL interface!\n",[32,696,697],{"class":34,"line":144},[32,698,296],{"class":128},[32,700,701],{"class":34,"line":149},[32,702,111],{"emptyLinePlaceholder":110},[32,704,705,707,710],{"class":34,"line":167},[32,706,170],{"class":117},[32,708,709],{"class":121}," nilTrap",[32,711,223],{"class":128},[32,713,714,717,720,722,724,727],{"class":34,"line":210},[32,715,716],{"class":128},"    l ",[32,718,719],{"class":117},":=",[32,721,622],{"class":121},[32,723,438],{"class":128},[32,725,726],{"class":444},"false",[32,728,729],{"class":128},")\n",[32,731,732,734,736,739,742,744,746],{"class":34,"line":215},[32,733,276],{"class":128},[32,735,279],{"class":121},[32,737,738],{"class":128},"(l ",[32,740,741],{"class":117},"==",[32,743,653],{"class":444},[32,745,508],{"class":128},[32,747,748],{"class":38},"\u002F\u002F false! The interface has a type, so it's non-nil.\n",[32,750,751,754],{"class":34,"line":226},[32,752,753],{"class":38},"    \u002F\u002F l.Log(\"hello\")",[32,755,756],{"class":38},"      \u002F\u002F panics: nil pointer dereference (the value is nil)\n",[32,758,759],{"class":34,"line":238},[32,760,296],{"class":128},[32,762,763],{"class":34,"line":261},[32,764,111],{"emptyLinePlaceholder":110},[32,766,767],{"class":34,"line":267},[32,768,769],{"class":38},"\u002F\u002F ✅ CORRECT: return nil directly for a nil interface:\n",[32,771,772,774,777,779,781,783,785,787],{"class":34,"line":273},[32,773,170],{"class":117},[32,775,776],{"class":121}," getLoggerFixed",[32,778,438],{"class":128},[32,780,627],{"class":176},[32,782,630],{"class":117},[32,784,183],{"class":128},[32,786,635],{"class":121},[32,788,371],{"class":128},[32,790,791,793,796],{"class":34,"line":293},[32,792,661],{"class":117},[32,794,795],{"class":117}," !",[32,797,798],{"class":128},"enabled {\n",[32,800,801,804,806],{"class":34,"line":514},[32,802,803],{"class":117},"        return",[32,805,653],{"class":444},[32,807,808],{"class":38},"  \u002F\u002F returns a true nil interface (type=nil, value=nil)\n",[32,810,811],{"class":34,"line":520},[32,812,683],{"class":128},[32,814,816,818,820,822],{"class":34,"line":815},28,[32,817,688],{"class":117},[32,819,674],{"class":117},[32,821,600],{"class":121},[32,823,585],{"class":128},[32,825,827],{"class":34,"line":826},29,[32,828,296],{"class":128},[32,830,832],{"class":34,"line":831},30,[32,833,111],{"emptyLinePlaceholder":110},[32,835,837,839,842],{"class":34,"line":836},31,[32,838,170],{"class":117},[32,840,841],{"class":121}," fixedDemo",[32,843,223],{"class":128},[32,845,847,849,851,853,855,857],{"class":34,"line":846},32,[32,848,716],{"class":128},[32,850,719],{"class":117},[32,852,776],{"class":121},[32,854,438],{"class":128},[32,856,726],{"class":444},[32,858,729],{"class":128},[32,860,862,864,866,868,870,872,874],{"class":34,"line":861},33,[32,863,276],{"class":128},[32,865,279],{"class":121},[32,867,738],{"class":128},[32,869,741],{"class":117},[32,871,653],{"class":444},[32,873,508],{"class":128},[32,875,876],{"class":38},"\u002F\u002F true\n",[32,878,880],{"class":34,"line":879},34,[32,881,296],{"class":128},[32,883,885],{"class":34,"line":884},35,[32,886,111],{"emptyLinePlaceholder":110},[32,888,890],{"class":34,"line":889},36,[32,891,892],{"class":38},"\u002F\u002F ┌──────────────────────────────────────────────────────────────────────┐\n",[32,894,896],{"class":34,"line":895},37,[32,897,898],{"class":38},"\u002F\u002F │ nil interface    │ (type=nil, value=nil) │ == nil → true             │\n",[32,900,902],{"class":34,"line":901},38,[32,903,904],{"class":38},"\u002F\u002F │ non-nil wrapping │ (type=*T,  value=nil) │ == nil → FALSE (the trap) │\n",[32,906,908],{"class":34,"line":907},39,[32,909,910],{"class":38},"\u002F\u002F │ Calling a method │ panics (nil pointer dereference)                  │\n",[32,912,914],{"class":34,"line":913},40,[32,915,916],{"class":38},"\u002F\u002F └──────────────────────────────────────────────────────────────────────┘\n",[14,918,920],{"id":919},"consumer-side-interface-definition","Consumer-Side Interface Definition",[19,922,923,1369,1373],{"language":21},[23,924,926],{"className":25,"code":925,"language":21,"meta":27,"style":27},"\u002F\u002F Go idiom: define interfaces where they're USED (consumer-side), not\n\u002F\u002F where types are DEFINED (producer-side).\n\u002F\u002F\n\u002F\u002F Why: the consumer knows what it needs. The producer shouldn't force\n\u002F\u002F every type to implement a giant interface \"just in case.\"\n\u002F\u002F\n\u002F\u002F \"The bigger the interface, the weaker the abstraction.\" — Rob Pike\n\n\u002F\u002F ❌ ANTI-PATTERN: producer-side giant interface\n\u002F\u002F package storage\n\u002F\u002F type Storage interface {\n\u002F\u002F     Get(ctx, key) (val, error)\n\u002F\u002F     Set(ctx, key, val) error\n\u002F\u002F     Delete(ctx, key) error\n\u002F\u002F     List(ctx, prefix) ([]string, error)\n\u002F\u002F     BatchGet(ctx, keys) (map[string]string, error)\n\u002F\u002F     Watch(ctx, key) (\u003C-chan Event, error)\n\u002F\u002F     \u002F\u002F ... 20 more methods\n\u002F\u002F }\n\u002F\u002F Every storage backend must implement ALL of these.\n\n\u002F\u002F ✅ CORRECT: consumer-side small interfaces\npackage cache\n\n\u002F\u002F The cache only needs Get and Set — define the minimal interface:\ntype Storage interface {\n    Get(ctx context.Context, key string) (string, error)\n    Set(ctx context.Context, key, val string) error\n}\n\ntype Cache struct {\n    storage Storage  \u002F\u002F accepts ANY type with Get and Set\n}\n\nfunc (c *Cache) GetOrSet(ctx context.Context, key string, load func() (string, error)) (string, error) {\n    val, err := c.storage.Get(ctx, key)\n    if err == nil {\n        return val, nil\n    }\n    val, err = load()\n    if err != nil {\n        return \"\", err\n    }\n    _ = c.storage.Set(ctx, key, val)\n    return val, nil\n}\n\n\u002F\u002F Now ANY storage backend (Redis, Memcached, Postgres, in-memory) that\n\u002F\u002F has Get and Set works with Cache — even types defined AFTER Cache.\n",[29,927,928,933,938,942,947,952,956,961,965,970,975,980,985,990,995,1000,1005,1010,1018,1023,1028,1032,1037,1045,1049,1054,1065,1105,1136,1140,1144,1155,1166,1170,1174,1237,1253,1266,1276,1280,1292,1306,1317,1322,1338,1347,1352,1357,1363],{"__ignoreMap":27},[32,929,930],{"class":34,"line":35},[32,931,932],{"class":38},"\u002F\u002F Go idiom: define interfaces where they're USED (consumer-side), not\n",[32,934,935],{"class":34,"line":42},[32,936,937],{"class":38},"\u002F\u002F where types are DEFINED (producer-side).\n",[32,939,940],{"class":34,"line":48},[32,941,69],{"class":38},[32,943,944],{"class":34,"line":54},[32,945,946],{"class":38},"\u002F\u002F Why: the consumer knows what it needs. The producer shouldn't force\n",[32,948,949],{"class":34,"line":60},[32,950,951],{"class":38},"\u002F\u002F every type to implement a giant interface \"just in case.\"\n",[32,953,954],{"class":34,"line":66},[32,955,69],{"class":38},[32,957,958],{"class":34,"line":72},[32,959,960],{"class":38},"\u002F\u002F \"The bigger the interface, the weaker the abstraction.\" — Rob Pike\n",[32,962,963],{"class":34,"line":78},[32,964,111],{"emptyLinePlaceholder":110},[32,966,967],{"class":34,"line":84},[32,968,969],{"class":38},"\u002F\u002F ❌ ANTI-PATTERN: producer-side giant interface\n",[32,971,972],{"class":34,"line":89},[32,973,974],{"class":38},"\u002F\u002F package storage\n",[32,976,977],{"class":34,"line":95},[32,978,979],{"class":38},"\u002F\u002F type Storage interface {\n",[32,981,982],{"class":34,"line":101},[32,983,984],{"class":38},"\u002F\u002F     Get(ctx, key) (val, error)\n",[32,986,987],{"class":34,"line":107},[32,988,989],{"class":38},"\u002F\u002F     Set(ctx, key, val) error\n",[32,991,992],{"class":34,"line":114},[32,993,994],{"class":38},"\u002F\u002F     Delete(ctx, key) error\n",[32,996,997],{"class":34,"line":144},[32,998,999],{"class":38},"\u002F\u002F     List(ctx, prefix) ([]string, error)\n",[32,1001,1002],{"class":34,"line":149},[32,1003,1004],{"class":38},"\u002F\u002F     BatchGet(ctx, keys) (map[string]string, error)\n",[32,1006,1007],{"class":34,"line":167},[32,1008,1009],{"class":38},"\u002F\u002F     Watch(ctx, key) (\u003C-chan Event, error)\n",[32,1011,1012,1015],{"class":34,"line":210},[32,1013,1014],{"class":38},"\u002F\u002F",[32,1016,1017],{"class":38},"     \u002F\u002F ... 20 more methods\n",[32,1019,1020],{"class":34,"line":215},[32,1021,1022],{"class":38},"\u002F\u002F }\n",[32,1024,1025],{"class":34,"line":226},[32,1026,1027],{"class":38},"\u002F\u002F Every storage backend must implement ALL of these.\n",[32,1029,1030],{"class":34,"line":238},[32,1031,111],{"emptyLinePlaceholder":110},[32,1033,1034],{"class":34,"line":261},[32,1035,1036],{"class":38},"\u002F\u002F ✅ CORRECT: consumer-side small interfaces\n",[32,1038,1039,1042],{"class":34,"line":267},[32,1040,1041],{"class":117},"package",[32,1043,1044],{"class":121}," cache\n",[32,1046,1047],{"class":34,"line":273},[32,1048,111],{"emptyLinePlaceholder":110},[32,1050,1051],{"class":34,"line":293},[32,1052,1053],{"class":38},"\u002F\u002F The cache only needs Get and Set — define the minimal interface:\n",[32,1055,1056,1058,1061,1063],{"class":34,"line":514},[32,1057,118],{"class":117},[32,1059,1060],{"class":121}," Storage",[32,1062,125],{"class":117},[32,1064,371],{"class":128},[32,1066,1067,1070,1072,1075,1078,1081,1084,1087,1090,1093,1096,1098,1100,1103],{"class":34,"line":520},[32,1068,1069],{"class":121},"    Get",[32,1071,438],{"class":128},[32,1073,1074],{"class":176},"ctx",[32,1076,1077],{"class":121}," context",[32,1079,1080],{"class":128},".",[32,1082,1083],{"class":121},"Context",[32,1085,1086],{"class":128},", ",[32,1088,1089],{"class":176},"key",[32,1091,1092],{"class":117}," string",[32,1094,1095],{"class":128},") (",[32,1097,138],{"class":117},[32,1099,1086],{"class":128},[32,1101,1102],{"class":117},"error",[32,1104,729],{"class":128},[32,1106,1107,1110,1112,1114,1116,1118,1120,1122,1124,1126,1129,1131,1133],{"class":34,"line":815},[32,1108,1109],{"class":121},"    Set",[32,1111,438],{"class":128},[32,1113,1074],{"class":176},[32,1115,1077],{"class":121},[32,1117,1080],{"class":128},[32,1119,1083],{"class":121},[32,1121,1086],{"class":128},[32,1123,1089],{"class":176},[32,1125,1086],{"class":128},[32,1127,1128],{"class":176},"val",[32,1130,1092],{"class":117},[32,1132,183],{"class":128},[32,1134,1135],{"class":117},"error\n",[32,1137,1138],{"class":34,"line":826},[32,1139,296],{"class":128},[32,1141,1142],{"class":34,"line":831},[32,1143,111],{"emptyLinePlaceholder":110},[32,1145,1146,1148,1151,1153],{"class":34,"line":836},[32,1147,118],{"class":117},[32,1149,1150],{"class":121}," Cache",[32,1152,157],{"class":117},[32,1154,371],{"class":128},[32,1156,1157,1160,1163],{"class":34,"line":846},[32,1158,1159],{"class":128},"    storage ",[32,1161,1162],{"class":121},"Storage",[32,1164,1165],{"class":38},"  \u002F\u002F accepts ANY type with Get and Set\n",[32,1167,1168],{"class":34,"line":861},[32,1169,296],{"class":128},[32,1171,1172],{"class":34,"line":879},[32,1173,111],{"emptyLinePlaceholder":110},[32,1175,1176,1178,1180,1182,1184,1187,1189,1192,1194,1196,1198,1200,1202,1204,1206,1208,1210,1213,1216,1219,1221,1223,1225,1228,1230,1232,1234],{"class":34,"line":884},[32,1177,170],{"class":117},[32,1179,173],{"class":128},[32,1181,413],{"class":176},[32,1183,597],{"class":117},[32,1185,1186],{"class":121},"Cache",[32,1188,183],{"class":128},[32,1190,1191],{"class":121},"GetOrSet",[32,1193,438],{"class":128},[32,1195,1074],{"class":176},[32,1197,1077],{"class":121},[32,1199,1080],{"class":128},[32,1201,1083],{"class":121},[32,1203,1086],{"class":128},[32,1205,1089],{"class":176},[32,1207,1092],{"class":117},[32,1209,1086],{"class":128},[32,1211,1212],{"class":176},"load",[32,1214,1215],{"class":117}," func",[32,1217,1218],{"class":128},"() (",[32,1220,138],{"class":117},[32,1222,1086],{"class":128},[32,1224,1102],{"class":117},[32,1226,1227],{"class":128},")) (",[32,1229,138],{"class":117},[32,1231,1086],{"class":128},[32,1233,1102],{"class":117},[32,1235,1236],{"class":128},") {\n",[32,1238,1239,1242,1244,1247,1250],{"class":34,"line":889},[32,1240,1241],{"class":128},"    val, err ",[32,1243,719],{"class":117},[32,1245,1246],{"class":128}," c.storage.",[32,1248,1249],{"class":121},"Get",[32,1251,1252],{"class":128},"(ctx, key)\n",[32,1254,1255,1257,1260,1262,1264],{"class":34,"line":895},[32,1256,661],{"class":117},[32,1258,1259],{"class":128}," err ",[32,1261,741],{"class":117},[32,1263,653],{"class":444},[32,1265,371],{"class":128},[32,1267,1268,1270,1273],{"class":34,"line":901},[32,1269,803],{"class":117},[32,1271,1272],{"class":128}," val, ",[32,1274,1275],{"class":444},"nil\n",[32,1277,1278],{"class":34,"line":907},[32,1279,683],{"class":128},[32,1281,1282,1284,1286,1289],{"class":34,"line":913},[32,1283,1241],{"class":128},[32,1285,244],{"class":117},[32,1287,1288],{"class":121}," load",[32,1290,1291],{"class":128},"()\n",[32,1293,1295,1297,1299,1302,1304],{"class":34,"line":1294},41,[32,1296,661],{"class":117},[32,1298,1259],{"class":128},[32,1300,1301],{"class":117},"!=",[32,1303,653],{"class":444},[32,1305,371],{"class":128},[32,1307,1309,1311,1314],{"class":34,"line":1308},42,[32,1310,803],{"class":117},[32,1312,1313],{"class":204}," \"\"",[32,1315,1316],{"class":128},", err\n",[32,1318,1320],{"class":34,"line":1319},43,[32,1321,683],{"class":128},[32,1323,1325,1328,1330,1332,1335],{"class":34,"line":1324},44,[32,1326,1327],{"class":128},"    _ ",[32,1329,244],{"class":117},[32,1331,1246],{"class":128},[32,1333,1334],{"class":121},"Set",[32,1336,1337],{"class":128},"(ctx, key, val)\n",[32,1339,1341,1343,1345],{"class":34,"line":1340},45,[32,1342,688],{"class":117},[32,1344,1272],{"class":128},[32,1346,1275],{"class":444},[32,1348,1350],{"class":34,"line":1349},46,[32,1351,296],{"class":128},[32,1353,1355],{"class":34,"line":1354},47,[32,1356,111],{"emptyLinePlaceholder":110},[32,1358,1360],{"class":34,"line":1359},48,[32,1361,1362],{"class":38},"\u002F\u002F Now ANY storage backend (Redis, Memcached, Postgres, in-memory) that\n",[32,1364,1366],{"class":34,"line":1365},49,[32,1367,1368],{"class":38},"\u002F\u002F has Get and Set works with Cache — even types defined AFTER Cache.\n",[14,1370,1372],{"id":1371},"accept-interfaces-return-structs","Accept Interfaces, Return Structs",[19,1374,1375,1606,1610],{"language":21},[23,1376,1378],{"className":25,"code":1377,"language":21,"meta":27,"style":27},"\u002F\u002F Go idiom: functions ACCEPT interface types (flexible, mockable) but\n\u002F\u002F RETURN concrete types (clear, inspectable).\n\u002F\u002F\n\u002F\u002F Accepting an interface lets callers pass any implementation.\n\u002F\u002F Returning a concrete type gives callers full access to the result.\n\n\u002F\u002F ✅ Accept interface, return concrete:\nfunc process(r io.Reader) *Result {  \u002F\u002F accepts any Reader\n    data, _ := io.ReadAll(r)\n    return &Result{data: data}  \u002F\u002F returns *Result (concrete, inspectable)\n}\n\n\u002F\u002F ❌ ANTI-PATTERN: return an interface (forces callers to type-assert)\nfunc processBad(r io.Reader) Resulter {  \u002F\u002F returns an interface\n    return &Result{data: data}\n}\n\u002F\u002F Caller must type-assert to use Result's fields:\n\u002F\u002F   r := processBad(reader)\n\u002F\u002F   if res, ok := r.(*Result); ok { ... }  \u002F\u002F awkward, loses type safety\n\n\u002F\u002F ❌ ANTI-PATTERN: accept concrete (inflexible, hard to test)\nfunc processBad2(f *os.File) *Result {  \u002F\u002F only accepts *os.File\n    \u002F\u002F Can't pass a bytes.Reader, a network connection, a test mock.\n    \u002F\u002F Unit testing requires a real file — painful.\n}\n",[29,1379,1380,1385,1390,1394,1399,1404,1408,1413,1446,1462,1476,1480,1484,1489,1516,1527,1531,1536,1541,1549,1553,1558,1592,1597,1602],{"__ignoreMap":27},[32,1381,1382],{"class":34,"line":35},[32,1383,1384],{"class":38},"\u002F\u002F Go idiom: functions ACCEPT interface types (flexible, mockable) but\n",[32,1386,1387],{"class":34,"line":42},[32,1388,1389],{"class":38},"\u002F\u002F RETURN concrete types (clear, inspectable).\n",[32,1391,1392],{"class":34,"line":48},[32,1393,69],{"class":38},[32,1395,1396],{"class":34,"line":54},[32,1397,1398],{"class":38},"\u002F\u002F Accepting an interface lets callers pass any implementation.\n",[32,1400,1401],{"class":34,"line":60},[32,1402,1403],{"class":38},"\u002F\u002F Returning a concrete type gives callers full access to the result.\n",[32,1405,1406],{"class":34,"line":66},[32,1407,111],{"emptyLinePlaceholder":110},[32,1409,1410],{"class":34,"line":72},[32,1411,1412],{"class":38},"\u002F\u002F ✅ Accept interface, return concrete:\n",[32,1414,1415,1417,1420,1422,1425,1428,1430,1433,1435,1437,1440,1443],{"class":34,"line":78},[32,1416,170],{"class":117},[32,1418,1419],{"class":121}," process",[32,1421,438],{"class":128},[32,1423,1424],{"class":176},"r",[32,1426,1427],{"class":121}," io",[32,1429,1080],{"class":128},[32,1431,1432],{"class":121},"Reader",[32,1434,183],{"class":128},[32,1436,597],{"class":117},[32,1438,1439],{"class":121},"Result",[32,1441,1442],{"class":128}," {  ",[32,1444,1445],{"class":38},"\u002F\u002F accepts any Reader\n",[32,1447,1448,1451,1453,1456,1459],{"class":34,"line":84},[32,1449,1450],{"class":128},"    data, _ ",[32,1452,719],{"class":117},[32,1454,1455],{"class":128}," io.",[32,1457,1458],{"class":121},"ReadAll",[32,1460,1461],{"class":128},"(r)\n",[32,1463,1464,1466,1468,1470,1473],{"class":34,"line":89},[32,1465,688],{"class":117},[32,1467,674],{"class":117},[32,1469,1439],{"class":121},[32,1471,1472],{"class":128},"{data: data}  ",[32,1474,1475],{"class":38},"\u002F\u002F returns *Result (concrete, inspectable)\n",[32,1477,1478],{"class":34,"line":95},[32,1479,296],{"class":128},[32,1481,1482],{"class":34,"line":101},[32,1483,111],{"emptyLinePlaceholder":110},[32,1485,1486],{"class":34,"line":107},[32,1487,1488],{"class":38},"\u002F\u002F ❌ ANTI-PATTERN: return an interface (forces callers to type-assert)\n",[32,1490,1491,1493,1496,1498,1500,1502,1504,1506,1508,1511,1513],{"class":34,"line":114},[32,1492,170],{"class":117},[32,1494,1495],{"class":121}," processBad",[32,1497,438],{"class":128},[32,1499,1424],{"class":176},[32,1501,1427],{"class":121},[32,1503,1080],{"class":128},[32,1505,1432],{"class":121},[32,1507,183],{"class":128},[32,1509,1510],{"class":121},"Resulter",[32,1512,1442],{"class":128},[32,1514,1515],{"class":38},"\u002F\u002F returns an interface\n",[32,1517,1518,1520,1522,1524],{"class":34,"line":144},[32,1519,688],{"class":117},[32,1521,674],{"class":117},[32,1523,1439],{"class":121},[32,1525,1526],{"class":128},"{data: data}\n",[32,1528,1529],{"class":34,"line":149},[32,1530,296],{"class":128},[32,1532,1533],{"class":34,"line":167},[32,1534,1535],{"class":38},"\u002F\u002F Caller must type-assert to use Result's fields:\n",[32,1537,1538],{"class":34,"line":210},[32,1539,1540],{"class":38},"\u002F\u002F   r := processBad(reader)\n",[32,1542,1543,1546],{"class":34,"line":215},[32,1544,1545],{"class":38},"\u002F\u002F   if res, ok := r.(*Result); ok { ... }",[32,1547,1548],{"class":38},"  \u002F\u002F awkward, loses type safety\n",[32,1550,1551],{"class":34,"line":226},[32,1552,111],{"emptyLinePlaceholder":110},[32,1554,1555],{"class":34,"line":238},[32,1556,1557],{"class":38},"\u002F\u002F ❌ ANTI-PATTERN: accept concrete (inflexible, hard to test)\n",[32,1559,1560,1562,1565,1567,1570,1573,1576,1578,1581,1583,1585,1587,1589],{"class":34,"line":261},[32,1561,170],{"class":117},[32,1563,1564],{"class":121}," processBad2",[32,1566,438],{"class":128},[32,1568,1569],{"class":176},"f",[32,1571,1572],{"class":117}," *",[32,1574,1575],{"class":121},"os",[32,1577,1080],{"class":128},[32,1579,1580],{"class":121},"File",[32,1582,183],{"class":128},[32,1584,597],{"class":117},[32,1586,1439],{"class":121},[32,1588,1442],{"class":128},[32,1590,1591],{"class":38},"\u002F\u002F only accepts *os.File\n",[32,1593,1594],{"class":34,"line":267},[32,1595,1596],{"class":38},"    \u002F\u002F Can't pass a bytes.Reader, a network connection, a test mock.\n",[32,1598,1599],{"class":34,"line":273},[32,1600,1601],{"class":38},"    \u002F\u002F Unit testing requires a real file — painful.\n",[32,1603,1604],{"class":34,"line":293},[32,1605,296],{"class":128},[14,1607,1609],{"id":1608},"interface-composition","Interface Composition",[19,1611,1612,1745,1753],{"language":21},[23,1613,1615],{"className":25,"code":1614,"language":21,"meta":27,"style":27},"\u002F\u002F Interfaces compose by embedding other interfaces:\ntype ReadWriter interface {\n    io.Reader   \u002F\u002F embeds Read(p []byte) (int, error)\n    io.Writer   \u002F\u002F embeds Write(p []byte) (int, error)\n}\n\ntype ReadWriteCloser interface {\n    io.Reader\n    io.Writer\n    io.Closer\n}\n\n\u002F\u002F The standard library uses this heavily:\n\u002F\u002F   io.ReadWriter      = Reader + Writer\n\u002F\u002F   io.ReadWriteCloser = Reader + Writer + Closer\n\u002F\u002F   io.ReadWriteSeeker = Reader + Writer + Seeker\n\n\u002F\u002F Small interfaces compose into larger ones. This is how Go avoids\n\u002F\u002F giant interfaces — compose the minimal pieces.\n",[29,1616,1617,1622,1633,1645,1657,1661,1665,1676,1685,1694,1703,1707,1711,1716,1721,1726,1731,1735,1740],{"__ignoreMap":27},[32,1618,1619],{"class":34,"line":35},[32,1620,1621],{"class":38},"\u002F\u002F Interfaces compose by embedding other interfaces:\n",[32,1623,1624,1626,1629,1631],{"class":34,"line":42},[32,1625,118],{"class":117},[32,1627,1628],{"class":121}," ReadWriter",[32,1630,125],{"class":117},[32,1632,371],{"class":128},[32,1634,1635,1638,1640,1642],{"class":34,"line":48},[32,1636,1637],{"class":121},"    io",[32,1639,1080],{"class":128},[32,1641,1432],{"class":121},[32,1643,1644],{"class":38},"   \u002F\u002F embeds Read(p []byte) (int, error)\n",[32,1646,1647,1649,1651,1654],{"class":34,"line":54},[32,1648,1637],{"class":121},[32,1650,1080],{"class":128},[32,1652,1653],{"class":121},"Writer",[32,1655,1656],{"class":38},"   \u002F\u002F embeds Write(p []byte) (int, error)\n",[32,1658,1659],{"class":34,"line":60},[32,1660,296],{"class":128},[32,1662,1663],{"class":34,"line":66},[32,1664,111],{"emptyLinePlaceholder":110},[32,1666,1667,1669,1672,1674],{"class":34,"line":72},[32,1668,118],{"class":117},[32,1670,1671],{"class":121}," ReadWriteCloser",[32,1673,125],{"class":117},[32,1675,371],{"class":128},[32,1677,1678,1680,1682],{"class":34,"line":78},[32,1679,1637],{"class":121},[32,1681,1080],{"class":128},[32,1683,1684],{"class":121},"Reader\n",[32,1686,1687,1689,1691],{"class":34,"line":84},[32,1688,1637],{"class":121},[32,1690,1080],{"class":128},[32,1692,1693],{"class":121},"Writer\n",[32,1695,1696,1698,1700],{"class":34,"line":89},[32,1697,1637],{"class":121},[32,1699,1080],{"class":128},[32,1701,1702],{"class":121},"Closer\n",[32,1704,1705],{"class":34,"line":95},[32,1706,296],{"class":128},[32,1708,1709],{"class":34,"line":101},[32,1710,111],{"emptyLinePlaceholder":110},[32,1712,1713],{"class":34,"line":107},[32,1714,1715],{"class":38},"\u002F\u002F The standard library uses this heavily:\n",[32,1717,1718],{"class":34,"line":114},[32,1719,1720],{"class":38},"\u002F\u002F   io.ReadWriter      = Reader + Writer\n",[32,1722,1723],{"class":34,"line":144},[32,1724,1725],{"class":38},"\u002F\u002F   io.ReadWriteCloser = Reader + Writer + Closer\n",[32,1727,1728],{"class":34,"line":149},[32,1729,1730],{"class":38},"\u002F\u002F   io.ReadWriteSeeker = Reader + Writer + Seeker\n",[32,1732,1733],{"class":34,"line":167},[32,1734,111],{"emptyLinePlaceholder":110},[32,1736,1737],{"class":34,"line":210},[32,1738,1739],{"class":38},"\u002F\u002F Small interfaces compose into larger ones. This is how Go avoids\n",[32,1741,1742],{"class":34,"line":215},[32,1743,1744],{"class":38},"\u002F\u002F giant interfaces — compose the minimal pieces.\n",[14,1746,1748,1749,1752],{"id":1747},"the-empty-interface-any-go-118","The Empty Interface ",[29,1750,1751],{},"any"," (Go 1.18+)",[19,1754,1755,1997,2001],{"language":21},[23,1756,1758],{"className":25,"code":1757,"language":21,"meta":27,"style":27},"\u002F\u002F `any` is an alias for `interface{}` (Go 1.18+). Every type satisfies it.\n\u002F\u002F It's the escape hatch for \"I don't know the type\" — but loses type safety.\n\nfunc anyDemo() {\n    var x any\n    x = 42\n    x = \"hello\"\n    x = []int{1, 2, 3}\n\n    \u002F\u002F To use the value, you MUST type-assert:\n    switch v := x.(type) {\n    case int:\n        fmt.Println(\"int:\", v)\n    case string:\n        fmt.Println(\"string:\", v)\n    default:\n        fmt.Printf(\"unknown: %T\\n\", v)\n    }\n}\n\n\u002F\u002F ⚠️ Avoid `any` when a specific interface works:\n\u002F\u002F ❌ func process(data any)  — caller can pass anything, you must assert\n\u002F\u002F ✅ func process(r io.Reader)  — caller must pass something readable\n\n\u002F\u002F Legitimate uses of `any`:\n\u002F\u002F   - fmt.Println(...any)  — printing any value (introspection)\n\u002F\u002F   - json.Marshal(any)    — encoding arbitrary JSON\n\u002F\u002F   - reflect package      — runtime type inspection\n\u002F\u002F   - Generic containers that truly hold anything (rare)\n",[29,1759,1760,1765,1770,1774,1783,1793,1803,1812,1842,1846,1851,1868,1879,1894,1902,1915,1922,1941,1945,1949,1953,1958,1963,1968,1972,1977,1982,1987,1992],{"__ignoreMap":27},[32,1761,1762],{"class":34,"line":35},[32,1763,1764],{"class":38},"\u002F\u002F `any` is an alias for `interface{}` (Go 1.18+). Every type satisfies it.\n",[32,1766,1767],{"class":34,"line":42},[32,1768,1769],{"class":38},"\u002F\u002F It's the escape hatch for \"I don't know the type\" — but loses type safety.\n",[32,1771,1772],{"class":34,"line":48},[32,1773,111],{"emptyLinePlaceholder":110},[32,1775,1776,1778,1781],{"class":34,"line":54},[32,1777,170],{"class":117},[32,1779,1780],{"class":121}," anyDemo",[32,1782,223],{"class":128},[32,1784,1785,1787,1790],{"class":34,"line":60},[32,1786,229],{"class":117},[32,1788,1789],{"class":128}," x ",[32,1791,1792],{"class":121},"any\n",[32,1794,1795,1798,1800],{"class":34,"line":66},[32,1796,1797],{"class":128},"    x ",[32,1799,244],{"class":117},[32,1801,1802],{"class":444}," 42\n",[32,1804,1805,1807,1809],{"class":34,"line":72},[32,1806,1797],{"class":128},[32,1808,244],{"class":117},[32,1810,1811],{"class":204}," \"hello\"\n",[32,1813,1814,1816,1818,1821,1824,1827,1830,1832,1835,1837,1840],{"class":34,"line":78},[32,1815,1797],{"class":128},[32,1817,244],{"class":117},[32,1819,1820],{"class":128}," []",[32,1822,1823],{"class":117},"int",[32,1825,1826],{"class":128},"{",[32,1828,1829],{"class":444},"1",[32,1831,1086],{"class":128},[32,1833,1834],{"class":444},"2",[32,1836,1086],{"class":128},[32,1838,1839],{"class":444},"3",[32,1841,296],{"class":128},[32,1843,1844],{"class":34,"line":84},[32,1845,111],{"emptyLinePlaceholder":110},[32,1847,1848],{"class":34,"line":89},[32,1849,1850],{"class":38},"    \u002F\u002F To use the value, you MUST type-assert:\n",[32,1852,1853,1856,1859,1861,1864,1866],{"class":34,"line":95},[32,1854,1855],{"class":117},"    switch",[32,1857,1858],{"class":128}," v ",[32,1860,719],{"class":117},[32,1862,1863],{"class":128}," x.(",[32,1865,118],{"class":117},[32,1867,1236],{"class":128},[32,1869,1870,1873,1876],{"class":34,"line":101},[32,1871,1872],{"class":117},"    case",[32,1874,1875],{"class":117}," int",[32,1877,1878],{"class":128},":\n",[32,1880,1881,1884,1886,1888,1891],{"class":34,"line":107},[32,1882,1883],{"class":128},"        fmt.",[32,1885,279],{"class":121},[32,1887,438],{"class":128},[32,1889,1890],{"class":204},"\"int:\"",[32,1892,1893],{"class":128},", v)\n",[32,1895,1896,1898,1900],{"class":34,"line":114},[32,1897,1872],{"class":117},[32,1899,1092],{"class":117},[32,1901,1878],{"class":128},[32,1903,1904,1906,1908,1910,1913],{"class":34,"line":144},[32,1905,1883],{"class":128},[32,1907,279],{"class":121},[32,1909,438],{"class":128},[32,1911,1912],{"class":204},"\"string:\"",[32,1914,1893],{"class":128},[32,1916,1917,1920],{"class":34,"line":149},[32,1918,1919],{"class":117},"    default",[32,1921,1878],{"class":128},[32,1923,1924,1926,1929,1931,1934,1937,1939],{"class":34,"line":167},[32,1925,1883],{"class":128},[32,1927,1928],{"class":121},"Printf",[32,1930,438],{"class":128},[32,1932,1933],{"class":204},"\"unknown: ",[32,1935,1936],{"class":444},"%T\\n",[32,1938,441],{"class":204},[32,1940,1893],{"class":128},[32,1942,1943],{"class":34,"line":210},[32,1944,683],{"class":128},[32,1946,1947],{"class":34,"line":215},[32,1948,296],{"class":128},[32,1950,1951],{"class":34,"line":226},[32,1952,111],{"emptyLinePlaceholder":110},[32,1954,1955],{"class":34,"line":238},[32,1956,1957],{"class":38},"\u002F\u002F ⚠️ Avoid `any` when a specific interface works:\n",[32,1959,1960],{"class":34,"line":261},[32,1961,1962],{"class":38},"\u002F\u002F ❌ func process(data any)  — caller can pass anything, you must assert\n",[32,1964,1965],{"class":34,"line":267},[32,1966,1967],{"class":38},"\u002F\u002F ✅ func process(r io.Reader)  — caller must pass something readable\n",[32,1969,1970],{"class":34,"line":273},[32,1971,111],{"emptyLinePlaceholder":110},[32,1973,1974],{"class":34,"line":293},[32,1975,1976],{"class":38},"\u002F\u002F Legitimate uses of `any`:\n",[32,1978,1979],{"class":34,"line":514},[32,1980,1981],{"class":38},"\u002F\u002F   - fmt.Println(...any)  — printing any value (introspection)\n",[32,1983,1984],{"class":34,"line":520},[32,1985,1986],{"class":38},"\u002F\u002F   - json.Marshal(any)    — encoding arbitrary JSON\n",[32,1988,1989],{"class":34,"line":815},[32,1990,1991],{"class":38},"\u002F\u002F   - reflect package      — runtime type inspection\n",[32,1993,1994],{"class":34,"line":826},[32,1995,1996],{"class":38},"\u002F\u002F   - Generic containers that truly hold anything (rare)\n",[14,1998,2000],{"id":1999},"production-pattern-interface-for-testability","Production Pattern — Interface for Testability",[19,2002,2003,2730,2734,2800,2804,2936,2940],{"language":21},[23,2004,2006],{"className":25,"code":2005,"language":21,"meta":27,"style":27},"\u002F\u002F ─── Define interfaces for external dependencies to enable mocking ───\n\n\u002F\u002F internal\u002Fstore\u002Fstore.go\ntype UserStore interface {\n    GetUser(ctx context.Context, id int64) (*User, error)\n    SaveUser(ctx context.Context, u *User) error\n}\n\n\u002F\u002F internal\u002Fstore\u002Fpostgres.go (production implementation)\ntype PostgresStore struct {\n    db *sql.DB\n}\nfunc (s *PostgresStore) GetUser(ctx context.Context, id int64) (*User, error) {\n    \u002F\u002F real DB query\n    return &User{}, nil\n}\nfunc (s *PostgresStore) SaveUser(ctx context.Context, u *User) error {\n    \u002F\u002F real DB insert\n    return nil\n}\n\n\u002F\u002F internal\u002Fservice\u002Fuser_service.go (uses the interface, not the concrete type)\ntype UserService struct {\n    store UserStore  \u002F\u002F accepts any UserStore — PostgresStore in prod, MockStore in tests\n}\n\nfunc (s *UserService) GetProfile(ctx context.Context, id int64) (*User, error) {\n    return s.store.GetUser(ctx, id)  \u002F\u002F testable with a mock\n}\n\n\u002F\u002F internal\u002Fservice\u002Fuser_service_test.go\ntype MockUserStore struct {\n    users map[int64]*User\n}\nfunc (m *MockUserStore) GetUser(ctx context.Context, id int64) (*User, error) {\n    if u, ok := m.users[id]; ok {\n        return u, nil\n    }\n    return nil, errors.New(\"not found\")\n}\nfunc (m *MockUserStore) SaveUser(ctx context.Context, u *User) error {\n    m.users[u.ID] = u\n    return nil\n}\n\nfunc TestGetProfile(t *testing.T) {\n    svc := &UserService{store: &MockUserStore{users: map[int64]*User{1: {ID: 1, Name: \"Alice\"}}}}\n    u, err := svc.GetProfile(context.Background(), 1)\n    if err != nil { t.Fatal(err) }\n    if u.Name != \"Alice\" { t.Errorf(\"expected Alice, got %s\", u.Name) }\n}\n",[29,2007,2008,2013,2017,2022,2033,2069,2097,2101,2105,2110,2121,2136,2140,2187,2192,2205,2209,2250,2255,2262,2266,2270,2275,2286,2297,2301,2305,2351,2366,2370,2374,2379,2390,2412,2416,2462,2474,2483,2487,2506,2510,2550,2560,2566,2570,2574,2598,2650,2675,2694,2725],{"__ignoreMap":27},[32,2009,2010],{"class":34,"line":35},[32,2011,2012],{"class":38},"\u002F\u002F ─── Define interfaces for external dependencies to enable mocking ───\n",[32,2014,2015],{"class":34,"line":42},[32,2016,111],{"emptyLinePlaceholder":110},[32,2018,2019],{"class":34,"line":48},[32,2020,2021],{"class":38},"\u002F\u002F internal\u002Fstore\u002Fstore.go\n",[32,2023,2024,2026,2029,2031],{"class":34,"line":54},[32,2025,118],{"class":117},[32,2027,2028],{"class":121}," UserStore",[32,2030,125],{"class":117},[32,2032,371],{"class":128},[32,2034,2035,2038,2040,2042,2044,2046,2048,2050,2053,2056,2058,2060,2063,2065,2067],{"class":34,"line":60},[32,2036,2037],{"class":121},"    GetUser",[32,2039,438],{"class":128},[32,2041,1074],{"class":176},[32,2043,1077],{"class":121},[32,2045,1080],{"class":128},[32,2047,1083],{"class":121},[32,2049,1086],{"class":128},[32,2051,2052],{"class":176},"id",[32,2054,2055],{"class":117}," int64",[32,2057,1095],{"class":128},[32,2059,597],{"class":117},[32,2061,2062],{"class":121},"User",[32,2064,1086],{"class":128},[32,2066,1102],{"class":117},[32,2068,729],{"class":128},[32,2070,2071,2074,2076,2078,2080,2082,2084,2086,2089,2091,2093,2095],{"class":34,"line":66},[32,2072,2073],{"class":121},"    SaveUser",[32,2075,438],{"class":128},[32,2077,1074],{"class":176},[32,2079,1077],{"class":121},[32,2081,1080],{"class":128},[32,2083,1083],{"class":121},[32,2085,1086],{"class":128},[32,2087,2088],{"class":176},"u",[32,2090,1572],{"class":117},[32,2092,2062],{"class":121},[32,2094,183],{"class":128},[32,2096,1135],{"class":117},[32,2098,2099],{"class":34,"line":72},[32,2100,296],{"class":128},[32,2102,2103],{"class":34,"line":78},[32,2104,111],{"emptyLinePlaceholder":110},[32,2106,2107],{"class":34,"line":84},[32,2108,2109],{"class":38},"\u002F\u002F internal\u002Fstore\u002Fpostgres.go (production implementation)\n",[32,2111,2112,2114,2117,2119],{"class":34,"line":89},[32,2113,118],{"class":117},[32,2115,2116],{"class":121}," PostgresStore",[32,2118,157],{"class":117},[32,2120,371],{"class":128},[32,2122,2123,2126,2128,2131,2133],{"class":34,"line":95},[32,2124,2125],{"class":128},"    db ",[32,2127,597],{"class":117},[32,2129,2130],{"class":121},"sql",[32,2132,1080],{"class":128},[32,2134,2135],{"class":121},"DB\n",[32,2137,2138],{"class":34,"line":101},[32,2139,296],{"class":128},[32,2141,2142,2144,2146,2149,2151,2154,2156,2159,2161,2163,2165,2167,2169,2171,2173,2175,2177,2179,2181,2183,2185],{"class":34,"line":107},[32,2143,170],{"class":117},[32,2145,173],{"class":128},[32,2147,2148],{"class":176},"s ",[32,2150,597],{"class":117},[32,2152,2153],{"class":121},"PostgresStore",[32,2155,183],{"class":128},[32,2157,2158],{"class":121},"GetUser",[32,2160,438],{"class":128},[32,2162,1074],{"class":176},[32,2164,1077],{"class":121},[32,2166,1080],{"class":128},[32,2168,1083],{"class":121},[32,2170,1086],{"class":128},[32,2172,2052],{"class":176},[32,2174,2055],{"class":117},[32,2176,1095],{"class":128},[32,2178,597],{"class":117},[32,2180,2062],{"class":121},[32,2182,1086],{"class":128},[32,2184,1102],{"class":117},[32,2186,1236],{"class":128},[32,2188,2189],{"class":34,"line":114},[32,2190,2191],{"class":38},"    \u002F\u002F real DB query\n",[32,2193,2194,2196,2198,2200,2203],{"class":34,"line":144},[32,2195,688],{"class":117},[32,2197,674],{"class":117},[32,2199,2062],{"class":121},[32,2201,2202],{"class":128},"{}, ",[32,2204,1275],{"class":444},[32,2206,2207],{"class":34,"line":149},[32,2208,296],{"class":128},[32,2210,2211,2213,2215,2217,2219,2221,2223,2226,2228,2230,2232,2234,2236,2238,2240,2242,2244,2246,2248],{"class":34,"line":167},[32,2212,170],{"class":117},[32,2214,173],{"class":128},[32,2216,2148],{"class":176},[32,2218,597],{"class":117},[32,2220,2153],{"class":121},[32,2222,183],{"class":128},[32,2224,2225],{"class":121},"SaveUser",[32,2227,438],{"class":128},[32,2229,1074],{"class":176},[32,2231,1077],{"class":121},[32,2233,1080],{"class":128},[32,2235,1083],{"class":121},[32,2237,1086],{"class":128},[32,2239,2088],{"class":176},[32,2241,1572],{"class":117},[32,2243,2062],{"class":121},[32,2245,183],{"class":128},[32,2247,1102],{"class":117},[32,2249,371],{"class":128},[32,2251,2252],{"class":34,"line":210},[32,2253,2254],{"class":38},"    \u002F\u002F real DB insert\n",[32,2256,2257,2259],{"class":34,"line":215},[32,2258,688],{"class":117},[32,2260,2261],{"class":444}," nil\n",[32,2263,2264],{"class":34,"line":226},[32,2265,296],{"class":128},[32,2267,2268],{"class":34,"line":238},[32,2269,111],{"emptyLinePlaceholder":110},[32,2271,2272],{"class":34,"line":261},[32,2273,2274],{"class":38},"\u002F\u002F internal\u002Fservice\u002Fuser_service.go (uses the interface, not the concrete type)\n",[32,2276,2277,2279,2282,2284],{"class":34,"line":267},[32,2278,118],{"class":117},[32,2280,2281],{"class":121}," UserService",[32,2283,157],{"class":117},[32,2285,371],{"class":128},[32,2287,2288,2291,2294],{"class":34,"line":273},[32,2289,2290],{"class":128},"    store ",[32,2292,2293],{"class":121},"UserStore",[32,2295,2296],{"class":38},"  \u002F\u002F accepts any UserStore — PostgresStore in prod, MockStore in tests\n",[32,2298,2299],{"class":34,"line":293},[32,2300,296],{"class":128},[32,2302,2303],{"class":34,"line":514},[32,2304,111],{"emptyLinePlaceholder":110},[32,2306,2307,2309,2311,2313,2315,2318,2320,2323,2325,2327,2329,2331,2333,2335,2337,2339,2341,2343,2345,2347,2349],{"class":34,"line":520},[32,2308,170],{"class":117},[32,2310,173],{"class":128},[32,2312,2148],{"class":176},[32,2314,597],{"class":117},[32,2316,2317],{"class":121},"UserService",[32,2319,183],{"class":128},[32,2321,2322],{"class":121},"GetProfile",[32,2324,438],{"class":128},[32,2326,1074],{"class":176},[32,2328,1077],{"class":121},[32,2330,1080],{"class":128},[32,2332,1083],{"class":121},[32,2334,1086],{"class":128},[32,2336,2052],{"class":176},[32,2338,2055],{"class":117},[32,2340,1095],{"class":128},[32,2342,597],{"class":117},[32,2344,2062],{"class":121},[32,2346,1086],{"class":128},[32,2348,1102],{"class":117},[32,2350,1236],{"class":128},[32,2352,2353,2355,2358,2360,2363],{"class":34,"line":815},[32,2354,688],{"class":117},[32,2356,2357],{"class":128}," s.store.",[32,2359,2158],{"class":121},[32,2361,2362],{"class":128},"(ctx, id)  ",[32,2364,2365],{"class":38},"\u002F\u002F testable with a mock\n",[32,2367,2368],{"class":34,"line":826},[32,2369,296],{"class":128},[32,2371,2372],{"class":34,"line":831},[32,2373,111],{"emptyLinePlaceholder":110},[32,2375,2376],{"class":34,"line":836},[32,2377,2378],{"class":38},"\u002F\u002F internal\u002Fservice\u002Fuser_service_test.go\n",[32,2380,2381,2383,2386,2388],{"class":34,"line":846},[32,2382,118],{"class":117},[32,2384,2385],{"class":121}," MockUserStore",[32,2387,157],{"class":117},[32,2389,371],{"class":128},[32,2391,2392,2395,2398,2401,2404,2407,2409],{"class":34,"line":861},[32,2393,2394],{"class":128},"    users ",[32,2396,2397],{"class":117},"map",[32,2399,2400],{"class":128},"[",[32,2402,2403],{"class":117},"int64",[32,2405,2406],{"class":128},"]",[32,2408,597],{"class":117},[32,2410,2411],{"class":121},"User\n",[32,2413,2414],{"class":34,"line":879},[32,2415,296],{"class":128},[32,2417,2418,2420,2422,2425,2427,2430,2432,2434,2436,2438,2440,2442,2444,2446,2448,2450,2452,2454,2456,2458,2460],{"class":34,"line":884},[32,2419,170],{"class":117},[32,2421,173],{"class":128},[32,2423,2424],{"class":176},"m ",[32,2426,597],{"class":117},[32,2428,2429],{"class":121},"MockUserStore",[32,2431,183],{"class":128},[32,2433,2158],{"class":121},[32,2435,438],{"class":128},[32,2437,1074],{"class":176},[32,2439,1077],{"class":121},[32,2441,1080],{"class":128},[32,2443,1083],{"class":121},[32,2445,1086],{"class":128},[32,2447,2052],{"class":176},[32,2449,2055],{"class":117},[32,2451,1095],{"class":128},[32,2453,597],{"class":117},[32,2455,2062],{"class":121},[32,2457,1086],{"class":128},[32,2459,1102],{"class":117},[32,2461,1236],{"class":128},[32,2463,2464,2466,2469,2471],{"class":34,"line":889},[32,2465,661],{"class":117},[32,2467,2468],{"class":128}," u, ok ",[32,2470,719],{"class":117},[32,2472,2473],{"class":128}," m.users[id]; ok {\n",[32,2475,2476,2478,2481],{"class":34,"line":895},[32,2477,803],{"class":117},[32,2479,2480],{"class":128}," u, ",[32,2482,1275],{"class":444},[32,2484,2485],{"class":34,"line":901},[32,2486,683],{"class":128},[32,2488,2489,2491,2493,2496,2499,2501,2504],{"class":34,"line":907},[32,2490,688],{"class":117},[32,2492,653],{"class":444},[32,2494,2495],{"class":128},", errors.",[32,2497,2498],{"class":121},"New",[32,2500,438],{"class":128},[32,2502,2503],{"class":204},"\"not found\"",[32,2505,729],{"class":128},[32,2507,2508],{"class":34,"line":913},[32,2509,296],{"class":128},[32,2511,2512,2514,2516,2518,2520,2522,2524,2526,2528,2530,2532,2534,2536,2538,2540,2542,2544,2546,2548],{"class":34,"line":1294},[32,2513,170],{"class":117},[32,2515,173],{"class":128},[32,2517,2424],{"class":176},[32,2519,597],{"class":117},[32,2521,2429],{"class":121},[32,2523,183],{"class":128},[32,2525,2225],{"class":121},[32,2527,438],{"class":128},[32,2529,1074],{"class":176},[32,2531,1077],{"class":121},[32,2533,1080],{"class":128},[32,2535,1083],{"class":121},[32,2537,1086],{"class":128},[32,2539,2088],{"class":176},[32,2541,1572],{"class":117},[32,2543,2062],{"class":121},[32,2545,183],{"class":128},[32,2547,1102],{"class":117},[32,2549,371],{"class":128},[32,2551,2552,2555,2557],{"class":34,"line":1308},[32,2553,2554],{"class":128},"    m.users[u.ID] ",[32,2556,244],{"class":117},[32,2558,2559],{"class":128}," u\n",[32,2561,2562,2564],{"class":34,"line":1319},[32,2563,688],{"class":117},[32,2565,2261],{"class":444},[32,2567,2568],{"class":34,"line":1324},[32,2569,296],{"class":128},[32,2571,2572],{"class":34,"line":1340},[32,2573,111],{"emptyLinePlaceholder":110},[32,2575,2576,2578,2581,2583,2586,2588,2591,2593,2596],{"class":34,"line":1349},[32,2577,170],{"class":117},[32,2579,2580],{"class":121}," TestGetProfile",[32,2582,438],{"class":128},[32,2584,2585],{"class":176},"t",[32,2587,1572],{"class":117},[32,2589,2590],{"class":121},"testing",[32,2592,1080],{"class":128},[32,2594,2595],{"class":121},"T",[32,2597,1236],{"class":128},[32,2599,2600,2603,2605,2607,2609,2612,2615,2617,2620,2622,2624,2626,2628,2630,2632,2634,2636,2639,2641,2644,2647],{"class":34,"line":1354},[32,2601,2602],{"class":128},"    svc ",[32,2604,719],{"class":117},[32,2606,674],{"class":117},[32,2608,2317],{"class":121},[32,2610,2611],{"class":128},"{store: ",[32,2613,2614],{"class":117},"&",[32,2616,2429],{"class":121},[32,2618,2619],{"class":128},"{users: ",[32,2621,2397],{"class":117},[32,2623,2400],{"class":128},[32,2625,2403],{"class":117},[32,2627,2406],{"class":128},[32,2629,597],{"class":117},[32,2631,2062],{"class":121},[32,2633,1826],{"class":128},[32,2635,1829],{"class":444},[32,2637,2638],{"class":128},": {ID: ",[32,2640,1829],{"class":444},[32,2642,2643],{"class":128},", Name: ",[32,2645,2646],{"class":204},"\"Alice\"",[32,2648,2649],{"class":128},"}}}}\n",[32,2651,2652,2655,2657,2660,2662,2665,2668,2671,2673],{"class":34,"line":1359},[32,2653,2654],{"class":128},"    u, err ",[32,2656,719],{"class":117},[32,2658,2659],{"class":128}," svc.",[32,2661,2322],{"class":121},[32,2663,2664],{"class":128},"(context.",[32,2666,2667],{"class":121},"Background",[32,2669,2670],{"class":128},"(), ",[32,2672,1829],{"class":444},[32,2674,729],{"class":128},[32,2676,2677,2679,2681,2683,2685,2688,2691],{"class":34,"line":1365},[32,2678,661],{"class":117},[32,2680,1259],{"class":128},[32,2682,1301],{"class":117},[32,2684,653],{"class":444},[32,2686,2687],{"class":128}," { t.",[32,2689,2690],{"class":121},"Fatal",[32,2692,2693],{"class":128},"(err) }\n",[32,2695,2697,2699,2702,2704,2707,2709,2712,2714,2717,2720,2722],{"class":34,"line":2696},50,[32,2698,661],{"class":117},[32,2700,2701],{"class":128}," u.Name ",[32,2703,1301],{"class":117},[32,2705,2706],{"class":204}," \"Alice\"",[32,2708,2687],{"class":128},[32,2710,2711],{"class":121},"Errorf",[32,2713,438],{"class":128},[32,2715,2716],{"class":204},"\"expected Alice, got ",[32,2718,2719],{"class":444},"%s",[32,2721,441],{"class":204},[32,2723,2724],{"class":128},", u.Name) }\n",[32,2726,2728],{"class":34,"line":2727},51,[32,2729,296],{"class":128},[14,2731,2733],{"id":2732},"tips-tricks","💡 Tips & Tricks",[2735,2736,2737,2749,2757,2762,2778,2795],"ul",{},[2738,2739,2740,2744,2745,2748],"li",{},[2741,2742,2743],"strong",{},"Idiom",": define interfaces where they're USED (consumer-side), not where types are defined — a function that needs ",[29,2746,2747],{},"io.Reader"," should declare it locally, not require types to implement a \"Readable\" interface in their package. Small, consumer-defined interfaces keep code decoupled.",[2738,2750,2751,2753,2754,2756],{},[2741,2752,2743],{},": keep interfaces small (1-3 methods) — \"the bigger the interface, the weaker the abstraction.\" ",[29,2755,2747],{}," (one method) is satisfied by hundreds of types; a 20-method interface is satisfied by one. Compose small interfaces.",[2738,2758,2759,2761],{},[2741,2760,2743],{},": accept interfaces, return concrete types — functions take interface parameters (flexible, mockable) but return concrete types (clear, inspectable). Returning an interface forces callers into type assertions.",[2738,2763,2764,2766,2767,2770,2771,2773,2774,2777],{},[2741,2765,2743],{},": ",[29,2768,2769],{},"var _ I = T{}"," as a compile-time assertion — catches breakage when a method is removed from ",[29,2772,2595],{}," or added to ",[29,2775,2776],{},"I",", at compile time. Common in library code.",[2738,2779,2780,2783,2784,2787,2788,2790,2791,2794],{},[2741,2781,2782],{},"Debug",": the nil-interface trap — ",[29,2785,2786],{},"var s Speaker = (*Dog)(nil); s == nil"," is ",[29,2789,726],{},". To return a nil interface, return ",[29,2792,2793],{},"nil"," directly, not a nil pointer of a concrete type. This is the #1 interface bug.",[2738,2796,2797,2799],{},[2741,2798,2743],{},": use interfaces for external dependencies (database, HTTP client, email sender) to enable testing with mocks — define the minimal interface the consumer needs, not the full API of the dependency.",[14,2801,2803],{"id":2802},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2735,2805,2806,2823,2840,2849,2867,2873,2895,2920],{},[2738,2807,2808,2766,2811,2787,2813,2815,2816,2819,2820,2822],{},[2741,2809,2810],{},"The nil interface trap",[29,2812,2786],{},[29,2814,726],{}," — the interface has a type (",[29,2817,2818],{},"*Dog","), so it's non-nil. Calling a method panics. Return ",[29,2821,2793],{}," directly for a nil interface.",[2738,2824,2825,2828,2829,2832,2833,2836,2837,1080],{},[2741,2826,2827],{},"Interfaces satisfied by method set",": a value type satisfies only value-receiver methods; a pointer type satisfies all methods. ",[29,2830,2831],{},"var s Speaker = T{}"," fails if ",[29,2834,2835],{},"Speaker"," requires a pointer-receiver method — use ",[29,2838,2839],{},"&T{}",[2738,2841,2842,2845,2846,2848],{},[2741,2843,2844],{},"Interface comparison",": interfaces are comparable with ",[29,2847,741],{}," if their dynamic types are comparable. Comparing interfaces holding slices\u002Fmaps\u002Ffunctions panics at runtime.",[2738,2850,2851,2856,2857,2859,2860,1086,2863,2866],{},[2741,2852,2853,2855],{},[29,2854,1751],{}," loses type safety",": you must type-assert to use the value. Prefer specific interfaces; reserve ",[29,2858,1751],{}," for genuine \"any value\" cases (",[29,2861,2862],{},"fmt",[29,2864,2865],{},"json",").",[2738,2868,2869,2872],{},[2741,2870,2871],{},"Interface values are immutable",": the interface holds a (type, value) pair; you can reassign the interface variable, but can't mutate the held value through the interface (unless the method mutates via a pointer).",[2738,2874,2875,2766,2878,2881,2882,2885,2886,2888,2889,2891,2892,2894],{},[2741,2876,2877],{},"Embedding an interface in a struct",[29,2879,2880],{},"type S struct { io.Reader }"," — ",[29,2883,2884],{},"S"," has a ",[29,2887,1432],{}," field (an interface); ",[29,2890,2884],{}," satisfies ",[29,2893,2747],{}," via promotion. Useful for decorating\u002Fdelegating.",[2738,2896,2897,2766,2900,2903,2904,2906,2907,2910,2911,2913,2914,2916,2917,2866],{},[2741,2898,2899],{},"Nil pointer receiver method call",[29,2901,2902],{},"var p *Dog; p.Speak()"," — if ",[29,2905,132],{}," has a value receiver, Go can't dereference ",[29,2908,2909],{},"p"," (nil) → panic. If ",[29,2912,132],{}," has a pointer receiver, it CAN be called on nil ",[29,2915,2818],{}," (the method can check ",[29,2918,2919],{},"p == nil",[2738,2921,2922,2766,2925,2928,2929,2932,2933,2935],{},[2741,2923,2924],{},"Interface boxing causes escape",[29,2926,2927],{},"var i any = x"," moves ",[29,2930,2931],{},"x"," to the heap. In hot paths, avoid passing values through ",[29,2934,1751],{}," — use concrete types to keep them on the stack.",[14,2937,2939],{"id":2938},"quick-quiz","🧠 Quick Quiz",[19,2941,2942,3104],{"language":21},[23,2943,2945],{"className":25,"code":2944,"language":21,"meta":27,"style":27},"type MyErr struct{}\nfunc (m *MyErr) Error() string { return \"my error\" }\n\nfunc doSomething(fail bool) error {\n    if fail {\n        var err *MyErr = nil\n        return err\n    }\n    return nil\n}\n\nfunc main() {\n    err := doSomething(true)\n    fmt.Println(err == nil)\n}\n",[29,2946,2947,2958,2989,2993,3013,3020,3035,3042,3046,3052,3056,3060,3069,3085,3100],{"__ignoreMap":27},[32,2948,2949,2951,2954,2956],{"class":34,"line":35},[32,2950,118],{"class":117},[32,2952,2953],{"class":121}," MyErr",[32,2955,157],{"class":117},[32,2957,585],{"class":128},[32,2959,2960,2962,2964,2966,2968,2971,2973,2976,2978,2980,2982,2984,2987],{"class":34,"line":42},[32,2961,170],{"class":117},[32,2963,173],{"class":128},[32,2965,2424],{"class":176},[32,2967,597],{"class":117},[32,2969,2970],{"class":121},"MyErr",[32,2972,183],{"class":128},[32,2974,2975],{"class":121},"Error",[32,2977,135],{"class":128},[32,2979,138],{"class":117},[32,2981,192],{"class":128},[32,2983,195],{"class":117},[32,2985,2986],{"class":204}," \"my error\"",[32,2988,141],{"class":128},[32,2990,2991],{"class":34,"line":48},[32,2992,111],{"emptyLinePlaceholder":110},[32,2994,2995,2997,3000,3002,3005,3007,3009,3011],{"class":34,"line":54},[32,2996,170],{"class":117},[32,2998,2999],{"class":121}," doSomething",[32,3001,438],{"class":128},[32,3003,3004],{"class":176},"fail",[32,3006,630],{"class":117},[32,3008,183],{"class":128},[32,3010,1102],{"class":117},[32,3012,371],{"class":128},[32,3014,3015,3017],{"class":34,"line":60},[32,3016,661],{"class":117},[32,3018,3019],{"class":128}," fail {\n",[32,3021,3022,3025,3027,3029,3031,3033],{"class":34,"line":66},[32,3023,3024],{"class":117},"        var",[32,3026,1259],{"class":128},[32,3028,597],{"class":117},[32,3030,2970],{"class":121},[32,3032,498],{"class":117},[32,3034,2261],{"class":444},[32,3036,3037,3039],{"class":34,"line":72},[32,3038,803],{"class":117},[32,3040,3041],{"class":128}," err\n",[32,3043,3044],{"class":34,"line":78},[32,3045,683],{"class":128},[32,3047,3048,3050],{"class":34,"line":84},[32,3049,688],{"class":117},[32,3051,2261],{"class":444},[32,3053,3054],{"class":34,"line":89},[32,3055,296],{"class":128},[32,3057,3058],{"class":34,"line":95},[32,3059,111],{"emptyLinePlaceholder":110},[32,3061,3062,3064,3067],{"class":34,"line":101},[32,3063,170],{"class":117},[32,3065,3066],{"class":121}," main",[32,3068,223],{"class":128},[32,3070,3071,3074,3076,3078,3080,3083],{"class":34,"line":107},[32,3072,3073],{"class":128},"    err ",[32,3075,719],{"class":117},[32,3077,2999],{"class":121},[32,3079,438],{"class":128},[32,3081,3082],{"class":444},"true",[32,3084,729],{"class":128},[32,3086,3087,3089,3091,3094,3096,3098],{"class":34,"line":114},[32,3088,276],{"class":128},[32,3090,279],{"class":121},[32,3092,3093],{"class":128},"(err ",[32,3095,741],{"class":117},[32,3097,653],{"class":444},[32,3099,729],{"class":128},[32,3101,3102],{"class":34,"line":144},[32,3103,296],{"class":128},[2909,3105,3106],{},"What's printed?",[3108,3109,3110,3114,3122,3159,3166,3172,3237],"details",{},[3111,3112,3113],"summary",{},"Answer",[23,3115,3120],{"className":3116,"code":3118,"language":3119},[3117],"language-text","false\n","text",[29,3121,3118],{"__ignoreMap":27},[2909,3123,3124,3127,3128,3131,3132,3134,3135,3138,3139,3141,3142,3144,3145,3147,3148,3150,3151,3153,3154,2787,3157,1080],{},[29,3125,3126],{},"doSomething(true)"," returns ",[29,3129,3130],{},"err"," where ",[29,3133,3130],{}," is a nil ",[29,3136,3137],{},"*MyErr",". But the return type is ",[29,3140,1102],{}," (an interface). Returning a nil ",[29,3143,3137],{}," into an ",[29,3146,1102],{}," interface creates a non-nil interface with type ",[29,3149,3137],{}," and value ",[29,3152,2793],{},". So ",[29,3155,3156],{},"err == nil",[29,3158,726],{},[2909,3160,3161,3162,3165],{},"This is the nil-interface trap applied to error returns. Calling ",[29,3163,3164],{},"err.Error()"," would panic (nil pointer dereference).",[2909,3167,3168,3169,3171],{},"The fix — return ",[29,3170,2793],{}," directly:",[23,3173,3175],{"className":25,"code":3174,"language":21,"meta":27,"style":27},"func doSomething(fail bool) error {\n    if fail {\n        return &MyErr{}  \u002F\u002F return a real error\n        \u002F\u002F or: return nil  \u002F\u002F if you meant \"no error\"\n    }\n    return nil\n}\n",[29,3176,3177,3195,3201,3215,3223,3227,3233],{"__ignoreMap":27},[32,3178,3179,3181,3183,3185,3187,3189,3191,3193],{"class":34,"line":35},[32,3180,170],{"class":117},[32,3182,2999],{"class":121},[32,3184,438],{"class":128},[32,3186,3004],{"class":176},[32,3188,630],{"class":117},[32,3190,183],{"class":128},[32,3192,1102],{"class":117},[32,3194,371],{"class":128},[32,3196,3197,3199],{"class":34,"line":42},[32,3198,661],{"class":117},[32,3200,3019],{"class":128},[32,3202,3203,3205,3207,3209,3212],{"class":34,"line":48},[32,3204,803],{"class":117},[32,3206,674],{"class":117},[32,3208,2970],{"class":121},[32,3210,3211],{"class":128},"{}  ",[32,3213,3214],{"class":38},"\u002F\u002F return a real error\n",[32,3216,3217,3220],{"class":34,"line":54},[32,3218,3219],{"class":38},"        \u002F\u002F or: return nil",[32,3221,3222],{"class":38},"  \u002F\u002F if you meant \"no error\"\n",[32,3224,3225],{"class":34,"line":60},[32,3226,683],{"class":128},[32,3228,3229,3231],{"class":34,"line":66},[32,3230,688],{"class":117},[32,3232,2261],{"class":444},[32,3234,3235],{"class":34,"line":72},[32,3236,296],{"class":128},[2909,3238,3239,3240,3242],{},"If you need to return a nil error explicitly, return ",[29,3241,2793],{}," (not a nil pointer of a concrete error type).",[14,3244,3246],{"id":3245},"whats-next","📚 What's Next",[2909,3248,3249,3250,3255],{},"→ ",[3251,3252,3254],"a",{"href":3253},"\u002Fgo\u002F13-type-assertions-and-switches","13 — Type Assertions & Type Switches"," — comma-ok assertions, type switch dispatch, interface-to-interface assertions, and JSON's float64 trap.",[3257,3258,3259],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}",{"title":27,"searchDepth":42,"depth":42,"links":3261},[3262,3263,3265],{"id":16,"depth":42,"text":17},{"id":299,"depth":42,"text":3264},"Implicit Satisfaction — No implements Keyword",{"id":3245,"depth":42,"text":3246},"Interface internals (type, value pair), the nil interface trap, implicit satisfaction, consumer-side interface definition, and the accept-interfaces-return-structs idiom.","md",{},"\u002Fgo\u002F12-interfaces",{"title":5,"description":3266},"go\u002F12-interfaces","HKG82lUuYjo973qAkPFSYYNRxPQgpFL_ilN14XY7Q-Y",1789924648488]