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