[{"data":1,"prerenderedAt":1672},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fgo-zero-values-e-value-semantics-vs-pointer-semantics":26},[4],{"title":5,"path":6,"stem":7,"children":8,"page":25},"Blog","\u002Fblog","blog",[9,13,17,21],{"title":10,"path":11,"stem":12},"Array ou slice? Capacidade, crescimento e as armadilhas do append","\u002Fblog\u002Farrays-e-slices-em-go-capacidade-crescimento-e-append","blog\u002Farrays-e-slices-em-go-capacidade-crescimento-e-append",{"title":14,"path":15,"stem":16},"Stack ou heap? Entendendo o escape analysis do Go","\u002Fblog\u002Fescape-analysis-em-go-stack-ou-heap","blog\u002Fescape-analysis-em-go-stack-ou-heap",{"title":18,"path":19,"stem":20},"Por que Go copia tudo? Zero Values e Pointer Semantics","\u002Fblog\u002Fgo-zero-values-e-value-semantics-vs-pointer-semantics","blog\u002Fgo-zero-values-e-value-semantics-vs-pointer-semantics",{"title":22,"path":23,"stem":24},"Nil map ou map vazio? Zero value, ordem de iteração e concorrência em Go","\u002Fblog\u002Fmaps-em-go-zero-value-ordem-de-iteracao-e-concorrencia","blog\u002Fmaps-em-go-zero-value-ordem-de-iteracao-e-concorrencia",false,{"id":27,"title":18,"author":28,"body":29,"date":1664,"description":1665,"extension":1666,"image":1667,"meta":1668,"minRead":1669,"navigation":179,"path":19,"seo":1670,"stem":20,"tags":28,"updatedAt":28,"__hash__":1671},"blog\u002Fblog\u002Fgo-zero-values-e-value-semantics-vs-pointer-semantics.md",null,{"type":30,"value":31,"toc":1649},"minimark",[32,49,52,57,60,123,134,140,224,231,234,248,251,255,258,349,356,359,437,443,536,542,547,554,561,608,614,659,666,690,693,753,763,767,777,886,903,1034,1041,1045,1052,1066,1191,1208,1224,1227,1243,1247,1254,1315,1339,1365,1369,1372,1379,1382,1444,1450,1463,1467,1476,1515,1529,1533,1536,1571,1574,1578,1645],[33,34,35,36,40,41,44,45,48],"p",{},"Se você está começando com Go vindo de outra linguagem, provavelmente já esbarrou em duas coisas que parecem simples mas mudam a forma como você escreve código: os ",[37,38,39],"strong",{},"zero values"," e a decisão entre passar dados ",[37,42,43],{},"por valor"," ou ",[37,46,47],{},"por ponteiro",".",[33,50,51],{},"À primeira vista são dois assuntos separados. Mas eles fazem parte da mesma filosofia da linguagem, e entender um ajuda a entender o outro. A proposta deste artigo é construir esse entendimento de forma gradual: primeiro o que é um zero value e por que ele existe, depois o que significam value e pointer semantics.",[53,54,56],"h2",{"id":55},"a-filosofia-do-go-variável-declarada-é-variável-pronta","A filosofia do Go: variável declarada é variável pronta!",[33,58,59],{},"Em muitas linguagens, declarar uma variável e não atribuir um valor a ela é um problema. Veja em C:",[61,62,67],"pre",{"className":63,"code":64,"language":65,"meta":66,"style":66},"language-c shiki shiki-themes material-theme-lighter github-light github-dark","int x;\nprintf(\"%d\\n\", x); \u002F\u002F valor imprevisível (\"lixo de memória\")\n","c","",[68,69,70,87],"code",{"__ignoreMap":66},[71,72,75,79,83],"span",{"class":73,"line":74},"line",1,[71,76,78],{"class":77},"sbsja","int",[71,80,82],{"class":81},"su5hD"," x",[71,84,86],{"class":85},"sP7_E",";\n",[71,88,90,94,97,101,105,109,111,114,116,119],{"class":73,"line":89},2,[71,91,93],{"class":92},"sGLFI","printf",[71,95,96],{"class":85},"(",[71,98,100],{"class":99},"sjJ54","\"",[71,102,104],{"class":103},"swQdS","%d",[71,106,108],{"class":107},"s_hVV","\\n",[71,110,100],{"class":99},[71,112,113],{"class":85},",",[71,115,82],{"class":81},[71,117,118],{"class":85},");",[71,120,122],{"class":121},"sutJx"," \u002F\u002F valor imprevisível (\"lixo de memória\")\n",[33,124,125,126,129,130,48],{},"Aqui ",[68,127,128],{},"x"," foi declarada, mas não inicializada. O que existe naquele endereço de memória é o que sobrou de antes, um valor imprevisível. Ler uma variável automática não inicializada é justamente o que a especificação da linguagem chama de ",[131,132,133],"em",{},"comportamento indefinido",[33,135,136,137,48],{},"Em Java o problema aparece de outra forma: campos de referência são inicializados automaticamente como ",[68,138,139],{},"null",[61,141,145],{"className":142,"code":143,"language":144,"meta":66,"style":66},"language-java shiki shiki-themes material-theme-lighter github-light github-dark","class Sessao {\n    User user;           \u002F\u002F campo de referência começa como null\n\n    void processar() {\n        user.getName();  \u002F\u002F NullPointerException em tempo de execução\n    }\n}\n","java",[68,146,147,159,174,181,195,212,218],{"__ignoreMap":66},[71,148,149,152,156],{"class":73,"line":74},[71,150,151],{"class":77},"class",[71,153,155],{"class":154},"sbgvK"," Sessao",[71,157,158],{"class":85}," {\n",[71,160,161,165,168,171],{"class":73,"line":89},[71,162,164],{"class":163},"s_bVq","    User",[71,166,167],{"class":81}," user",[71,169,170],{"class":85},";",[71,172,173],{"class":121},"           \u002F\u002F campo de referência começa como null\n",[71,175,177],{"class":73,"line":176},3,[71,178,180],{"emptyLinePlaceholder":179},true,"\n",[71,182,184,187,190,193],{"class":73,"line":183},4,[71,185,186],{"class":77},"    void",[71,188,189],{"class":92}," processar",[71,191,192],{"class":85},"()",[71,194,158],{"class":85},[71,196,198,201,203,206,209],{"class":73,"line":197},5,[71,199,200],{"class":81},"        user",[71,202,48],{"class":85},[71,204,205],{"class":92},"getName",[71,207,208],{"class":85},"();",[71,210,211],{"class":121},"  \u002F\u002F NullPointerException em tempo de execução\n",[71,213,215],{"class":73,"line":214},6,[71,216,217],{"class":85},"    }\n",[71,219,221],{"class":73,"line":220},7,[71,222,223],{"class":85},"}\n",[33,225,226,227,230],{},"O resultado é que você acaba escrevendo verificações defensivas em todo lugar (",[68,228,229],{},"if (user != null)",") para não quebrar em produção.",[33,232,233],{},"Go decidiu resolver isso na raiz com uma regra simples:",[235,236,237],"note",{},[33,238,239,240,243,244,247],{},"Toda variável declarada em Go ",[37,241,242],{},"sempre"," recebe um valor inicial bem definido, mesmo que você não atribua nada. Esse valor é o ",[37,245,246],{},"zero value"," do tipo.",[33,249,250],{},"Não existe \"lixo de memória\" e não existe variável não inicializada. Isso não é um detalhe de implementação, é uma decisão de design pensada para que o código seja previsível por padrão.",[53,252,254],{"id":253},"parte-1-o-que-são-zero-values","Parte 1: O que são Zero Values",[33,256,257],{},"Quando você declara uma variável sem valor, Go a inicializa com o zero value do tipo dela:",[61,259,263],{"className":260,"code":261,"language":262,"meta":66,"style":66},"language-go shiki shiki-themes material-theme-lighter github-light github-dark","var age int       \u002F\u002F 0\nvar price float64   \u002F\u002F 0.0\nvar name string     \u002F\u002F \"\" (string vazia)\nvar active bool      \u002F\u002F false\nvar list []int     \u002F\u002F nil\nvar user *User   \u002F\u002F nil\n","go",[68,264,265,279,292,305,318,333],{"__ignoreMap":66},[71,266,267,271,274,276],{"class":73,"line":74},[71,268,270],{"class":269},"smGrS","var",[71,272,273],{"class":81}," age ",[71,275,78],{"class":77},[71,277,278],{"class":121},"       \u002F\u002F 0\n",[71,280,281,283,286,289],{"class":73,"line":89},[71,282,270],{"class":269},[71,284,285],{"class":81}," price ",[71,287,288],{"class":77},"float64",[71,290,291],{"class":121},"   \u002F\u002F 0.0\n",[71,293,294,296,299,302],{"class":73,"line":176},[71,295,270],{"class":269},[71,297,298],{"class":81}," name ",[71,300,301],{"class":77},"string",[71,303,304],{"class":121},"     \u002F\u002F \"\" (string vazia)\n",[71,306,307,309,312,315],{"class":73,"line":183},[71,308,270],{"class":269},[71,310,311],{"class":81}," active ",[71,313,314],{"class":77},"bool",[71,316,317],{"class":121},"      \u002F\u002F false\n",[71,319,320,322,325,328,330],{"class":73,"line":197},[71,321,270],{"class":269},[71,323,324],{"class":81}," list ",[71,326,327],{"class":85},"[]",[71,329,78],{"class":77},[71,331,332],{"class":121},"     \u002F\u002F nil\n",[71,334,335,337,340,343,346],{"class":73,"line":214},[71,336,270],{"class":269},[71,338,339],{"class":81}," user ",[71,341,342],{"class":269},"*",[71,344,345],{"class":154},"User",[71,347,348],{"class":121},"   \u002F\u002F nil\n",[33,350,351,352,355],{},"O zero value é ",[37,353,354],{},"determinístico",": para um dado tipo, ele é sempre o mesmo. Isso significa que você pode raciocinar sobre o estado inicial de qualquer variável só olhando o tipo dela.",[33,357,358],{},"Aqui está a tabela que vale a pena guardar:",[360,361,362,375],"table",{},[363,364,365],"thead",{},[366,367,368,372],"tr",{},[369,370,371],"th",{},"Categoria de tipo",[369,373,374],{},"Zero value",[376,377,378,395,406,417,427],"tbody",{},[366,379,380,390],{},[381,382,383,384,386,387,389],"td",{},"Numéricos (",[68,385,78],{},", ",[68,388,288],{},", ...)",[381,391,392],{},[68,393,394],{},"0",[366,396,397,401],{},[381,398,399],{},[68,400,314],{},[381,402,403],{},[68,404,405],{},"false",[366,407,408,412],{},[381,409,410],{},[68,411,301],{},[381,413,414],{},[68,415,416],{},"\"\"",[366,418,419,422],{},[381,420,421],{},"Ponteiros, slices, maps, channels, funcs, interfaces",[381,423,424],{},[68,425,426],{},"nil",[366,428,429,434],{},[381,430,431],{},[68,432,433],{},"struct",[381,435,436],{},"cada campo com seu próprio zero value",[33,438,439,440,442],{},"O caso do ",[68,441,433],{}," é o mais interessante, porque a regra se aplica recursivamente:",[61,444,446],{"className":260,"code":445,"language":262,"meta":66,"style":66},"type User struct {\n    Nome  string\n    Idade int\n    Ativo bool\n}\n\nvar u User\nfmt.Printf(\"%+v\\n\", u) \u002F\u002F {Nome: Idade:0 Ativo:false}\n",[68,447,448,461,469,477,485,489,493,503],{"__ignoreMap":66},[71,449,450,453,456,459],{"class":73,"line":74},[71,451,452],{"class":269},"type",[71,454,455],{"class":154}," User",[71,457,458],{"class":269}," struct",[71,460,158],{"class":85},[71,462,463,466],{"class":73,"line":89},[71,464,465],{"class":81},"    Nome  ",[71,467,468],{"class":77},"string\n",[71,470,471,474],{"class":73,"line":176},[71,472,473],{"class":81},"    Idade ",[71,475,476],{"class":77},"int\n",[71,478,479,482],{"class":73,"line":183},[71,480,481],{"class":81},"    Ativo ",[71,483,484],{"class":77},"bool\n",[71,486,487],{"class":73,"line":197},[71,488,223],{"class":85},[71,490,491],{"class":73,"line":214},[71,492,180],{"emptyLinePlaceholder":179},[71,494,495,497,500],{"class":73,"line":220},[71,496,270],{"class":269},[71,498,499],{"class":81}," u ",[71,501,502],{"class":154},"User\n",[71,504,506,509,511,514,516,518,521,523,525,527,530,533],{"class":73,"line":505},8,[71,507,508],{"class":81},"fmt",[71,510,48],{"class":85},[71,512,513],{"class":92},"Printf",[71,515,96],{"class":85},[71,517,100],{"class":99},[71,519,520],{"class":103},"%+v",[71,522,108],{"class":107},[71,524,100],{"class":99},[71,526,113],{"class":85},[71,528,529],{"class":81}," u",[71,531,532],{"class":85},")",[71,534,535],{"class":121}," \u002F\u002F {Nome: Idade:0 Ativo:false}\n",[33,537,538,539,541],{},"Não precisei escrever um construtor nem inicializar campo por campo. A ",[68,540,433],{}," já nasce em um estado válido e conhecido.",[543,544,546],"h3",{"id":545},"o-padrão-do-zero-value-útil","O padrão do \"zero value útil\"",[33,548,549,550,553],{},"Em Go, um bom design faz o zero value ser ",[37,551,552],{},"imediatamente utilizável",", sem exigir inicialização.",[33,555,556,557,560],{},"O exemplo clássico é ",[68,558,559],{},"sync.Mutex",":",[61,562,564],{"className":260,"code":563,"language":262,"meta":66,"style":66},"var mu sync.Mutex\nmu.Lock()   \u002F\u002F funciona. Não precisou de sync.NewMutex()\nmu.Unlock()\n",[68,565,566,581,596],{"__ignoreMap":66},[71,567,568,570,573,576,578],{"class":73,"line":74},[71,569,270],{"class":269},[71,571,572],{"class":81}," mu ",[71,574,575],{"class":154},"sync",[71,577,48],{"class":85},[71,579,580],{"class":154},"Mutex\n",[71,582,583,586,588,591,593],{"class":73,"line":89},[71,584,585],{"class":81},"mu",[71,587,48],{"class":85},[71,589,590],{"class":92},"Lock",[71,592,192],{"class":85},[71,594,595],{"class":121},"   \u002F\u002F funciona. Não precisou de sync.NewMutex()\n",[71,597,598,600,602,605],{"class":73,"line":176},[71,599,585],{"class":81},[71,601,48],{"class":85},[71,603,604],{"class":92},"Unlock",[71,606,607],{"class":85},"()\n",[33,609,610,611,560],{},"O mesmo vale para ",[68,612,613],{},"bytes.Buffer",[61,615,617],{"className":260,"code":616,"language":262,"meta":66,"style":66},"var buf bytes.Buffer\nbuf.WriteString(\"olá\") \u002F\u002F já funciona, buffer vazio é um estado válido\n",[68,618,619,634],{"__ignoreMap":66},[71,620,621,623,626,629,631],{"class":73,"line":74},[71,622,270],{"class":269},[71,624,625],{"class":81}," buf ",[71,627,628],{"class":154},"bytes",[71,630,48],{"class":85},[71,632,633],{"class":154},"Buffer\n",[71,635,636,639,641,644,646,648,652,654,656],{"class":73,"line":89},[71,637,638],{"class":81},"buf",[71,640,48],{"class":85},[71,642,643],{"class":92},"WriteString",[71,645,96],{"class":85},[71,647,100],{"class":99},[71,649,651],{"class":650},"s_sjI","olá",[71,653,100],{"class":99},[71,655,532],{"class":85},[71,657,658],{"class":121}," \u002F\u002F já funciona, buffer vazio é um estado válido\n",[33,660,661,662,665],{},"Quando você projetar suas próprias structs, vale perguntar: ",[131,663,664],{},"\"o zero value dessa struct faz sentido sozinho?\"",". Se a resposta for sim, você poupa quem usa seu código de uma etapa de inicialização.",[667,668,669],"tip",{},[33,670,671,672,675,676,678,679,681,682,685,686,689],{},"Nem todo zero value é útil de imediato. Um ",[68,673,674],{},"map"," com zero value é ",[68,677,426],{},", e escrever em um map ",[68,680,426],{}," causa ",[37,683,684],{},"panic",". Nesses casos você ainda precisa inicializar com ",[68,687,688],{},"make(map[string]int)",". Ler de um map nil, porém, é seguro e retorna o zero value.",[33,691,692],{},"Antes de seguir, uma armadilha comum que combina zero value com um dos temas do próximo tópico:",[61,694,696],{"className":260,"code":695,"language":262,"meta":66,"style":66},"var list []int\nlist = append(list, 1) \u002F\u002F OK! append lida com slice nil de boa\nfmt.Println(list)        \u002F\u002F [1]\n",[68,697,698,708,735],{"__ignoreMap":66},[71,699,700,702,704,706],{"class":73,"line":74},[71,701,270],{"class":269},[71,703,324],{"class":81},[71,705,327],{"class":85},[71,707,476],{"class":77},[71,709,710,713,716,719,721,724,726,730,732],{"class":73,"line":89},[71,711,712],{"class":81},"list ",[71,714,715],{"class":269},"=",[71,717,718],{"class":92}," append",[71,720,96],{"class":85},[71,722,723],{"class":81},"list",[71,725,113],{"class":85},[71,727,729],{"class":728},"srdBf"," 1",[71,731,532],{"class":85},[71,733,734],{"class":121}," \u002F\u002F OK! append lida com slice nil de boa\n",[71,736,737,739,741,744,746,748,750],{"class":73,"line":176},[71,738,508],{"class":81},[71,740,48],{"class":85},[71,742,743],{"class":92},"Println",[71,745,96],{"class":85},[71,747,723],{"class":81},[71,749,532],{"class":85},[71,751,752],{"class":121},"        \u002F\u002F [1]\n",[33,754,755,756,758,759,762],{},"Um slice ",[68,757,426],{}," tem comprimento zero e você pode dar ",[68,760,761],{},"append"," nele normalmente. Isso é diferente do map, e é o tipo de detalhe que só fica natural com o tempo.",[53,764,766],{"id":765},"parte-2-value-semantics","Parte 2: Value Semantics",[33,768,769,770,773,774,48],{},"Agora vamos à segunda metade. Em Go, quando você passa um valor para uma função ou atribui a outra variável, ",[37,771,772],{},"por padrão uma cópia é feita",". Isso é o que chamamos de ",[131,775,776],{},"value semantics",[61,778,780],{"className":260,"code":779,"language":262,"meta":66,"style":66},"func dobrar(n int) {\n    n = n * 2 \u002F\u002F altera a CÓPIA local\n}\n\nfunc main() {\n    x := 10\n    dobrar(x)\n    fmt.Println(x) \u002F\u002F 10 — o original não mudou\n}\n",[68,781,782,803,821,825,829,840,851,863,881],{"__ignoreMap":66},[71,783,784,787,790,792,796,799,801],{"class":73,"line":74},[71,785,786],{"class":269},"func",[71,788,789],{"class":92}," dobrar",[71,791,96],{"class":85},[71,793,795],{"class":794},"s99_P","n",[71,797,798],{"class":77}," int",[71,800,532],{"class":85},[71,802,158],{"class":85},[71,804,805,808,810,813,815,818],{"class":73,"line":89},[71,806,807],{"class":81},"    n ",[71,809,715],{"class":269},[71,811,812],{"class":81}," n ",[71,814,342],{"class":269},[71,816,817],{"class":728}," 2",[71,819,820],{"class":121}," \u002F\u002F altera a CÓPIA local\n",[71,822,823],{"class":73,"line":176},[71,824,223],{"class":85},[71,826,827],{"class":73,"line":183},[71,828,180],{"emptyLinePlaceholder":179},[71,830,831,833,836,838],{"class":73,"line":197},[71,832,786],{"class":269},[71,834,835],{"class":92}," main",[71,837,192],{"class":85},[71,839,158],{"class":85},[71,841,842,845,848],{"class":73,"line":214},[71,843,844],{"class":81},"    x ",[71,846,847],{"class":269},":=",[71,849,850],{"class":728}," 10\n",[71,852,853,856,858,860],{"class":73,"line":220},[71,854,855],{"class":92},"    dobrar",[71,857,96],{"class":85},[71,859,128],{"class":81},[71,861,862],{"class":85},")\n",[71,864,865,868,870,872,874,876,878],{"class":73,"line":505},[71,866,867],{"class":81},"    fmt",[71,869,48],{"class":85},[71,871,743],{"class":92},[71,873,96],{"class":85},[71,875,128],{"class":81},[71,877,532],{"class":85},[71,879,880],{"class":121}," \u002F\u002F 10 — o original não mudou\n",[71,882,884],{"class":73,"line":883},9,[71,885,223],{"class":85},[33,887,888,889,892,893,895,896,898,899,902],{},"A função ",[68,890,891],{},"dobrar"," recebeu uma cópia de ",[68,894,128],{},". Alterá-la lá dentro não tem efeito nenhum sobre o ",[68,897,128],{}," do ",[68,900,901],{},"main",". O mesmo acontece com structs:",[61,904,906],{"className":260,"code":905,"language":262,"meta":66,"style":66},"func aniversario(u User) {\n    u.Idade++ \u002F\u002F altera a cópia\n}\n\nfunc main() {\n    joao := User{Nome: \"João\", Idade: 30}\n    aniversario(joao)\n    fmt.Println(joao.Idade) \u002F\u002F 30 — inalterado\n}\n",[68,907,908,926,942,946,950,960,997,1009,1030],{"__ignoreMap":66},[71,909,910,912,915,917,920,922,924],{"class":73,"line":74},[71,911,786],{"class":269},[71,913,914],{"class":92}," aniversario",[71,916,96],{"class":85},[71,918,919],{"class":794},"u",[71,921,455],{"class":154},[71,923,532],{"class":85},[71,925,158],{"class":85},[71,927,928,931,933,936,939],{"class":73,"line":89},[71,929,930],{"class":81},"    u",[71,932,48],{"class":85},[71,934,935],{"class":81},"Idade",[71,937,938],{"class":269},"++",[71,940,941],{"class":121}," \u002F\u002F altera a cópia\n",[71,943,944],{"class":73,"line":176},[71,945,223],{"class":85},[71,947,948],{"class":73,"line":183},[71,949,180],{"emptyLinePlaceholder":179},[71,951,952,954,956,958],{"class":73,"line":197},[71,953,786],{"class":269},[71,955,835],{"class":92},[71,957,192],{"class":85},[71,959,158],{"class":85},[71,961,962,965,967,969,972,975,977,980,983,985,987,990,992,995],{"class":73,"line":214},[71,963,964],{"class":81},"    joao ",[71,966,847],{"class":269},[71,968,455],{"class":154},[71,970,971],{"class":85},"{",[71,973,974],{"class":81},"Nome",[71,976,560],{"class":85},[71,978,979],{"class":99}," \"",[71,981,982],{"class":650},"João",[71,984,100],{"class":99},[71,986,113],{"class":85},[71,988,989],{"class":81}," Idade",[71,991,560],{"class":85},[71,993,994],{"class":728}," 30",[71,996,223],{"class":85},[71,998,999,1002,1004,1007],{"class":73,"line":220},[71,1000,1001],{"class":92},"    aniversario",[71,1003,96],{"class":85},[71,1005,1006],{"class":81},"joao",[71,1008,862],{"class":85},[71,1010,1011,1013,1015,1017,1019,1021,1023,1025,1027],{"class":73,"line":505},[71,1012,867],{"class":81},[71,1014,48],{"class":85},[71,1016,743],{"class":92},[71,1018,96],{"class":85},[71,1020,1006],{"class":81},[71,1022,48],{"class":85},[71,1024,935],{"class":81},[71,1026,532],{"class":85},[71,1028,1029],{"class":121}," \u002F\u002F 30 — inalterado\n",[71,1031,1032],{"class":73,"line":883},[71,1033,223],{"class":85},[33,1035,1036,1037,1040],{},"A vantagem de value semantics é o ",[37,1038,1039],{},"isolamento",": cada função trabalha com seu próprio dado e não há como uma parte do código modificar acidentalmente um valor que pertence a outra. O código fica mais fácil de raciocinar, porque você sabe que passar algo adiante não vai alterá-lo pelas suas costas.",[53,1042,1044],{"id":1043},"parte-3-pointer-semantics","Parte 3: Pointer Semantics",[33,1046,1047,1048,1051],{},"Mas e quando você ",[131,1049,1050],{},"quer"," que a alteração seja refletida no original? Ou quando copiar o dado inteiro seria caro? É aí que entram os ponteiros.",[33,1053,1054,1055,1058,1059,1062,1063,1065],{},"Um ponteiro guarda o ",[37,1056,1057],{},"endereço"," de um valor, não o valor em si. Usamos ",[68,1060,1061],{},"&"," para pegar o endereço de uma variável e ",[68,1064,342],{}," para acessar o valor apontado.",[61,1067,1069],{"className":260,"code":1068,"language":262,"meta":66,"style":66},"func aniversario(u *User) {\n    u.Idade++ \u002F\u002F altera o ORIGINAL, através do endereço\n}\n\nfunc main() {\n    joao := User{Nome: \"João\", Idade: 30}\n    aniversario(&joao)      \u002F\u002F passamos o endereço\n    fmt.Println(joao.Idade) \u002F\u002F 31 — mudou de verdade\n}\n",[68,1070,1071,1090,1103,1107,1111,1121,1151,1166,1187],{"__ignoreMap":66},[71,1072,1073,1075,1077,1079,1081,1084,1086,1088],{"class":73,"line":74},[71,1074,786],{"class":269},[71,1076,914],{"class":92},[71,1078,96],{"class":85},[71,1080,919],{"class":794},[71,1082,1083],{"class":269}," *",[71,1085,345],{"class":154},[71,1087,532],{"class":85},[71,1089,158],{"class":85},[71,1091,1092,1094,1096,1098,1100],{"class":73,"line":89},[71,1093,930],{"class":81},[71,1095,48],{"class":85},[71,1097,935],{"class":81},[71,1099,938],{"class":269},[71,1101,1102],{"class":121}," \u002F\u002F altera o ORIGINAL, através do endereço\n",[71,1104,1105],{"class":73,"line":176},[71,1106,223],{"class":85},[71,1108,1109],{"class":73,"line":183},[71,1110,180],{"emptyLinePlaceholder":179},[71,1112,1113,1115,1117,1119],{"class":73,"line":197},[71,1114,786],{"class":269},[71,1116,835],{"class":92},[71,1118,192],{"class":85},[71,1120,158],{"class":85},[71,1122,1123,1125,1127,1129,1131,1133,1135,1137,1139,1141,1143,1145,1147,1149],{"class":73,"line":214},[71,1124,964],{"class":81},[71,1126,847],{"class":269},[71,1128,455],{"class":154},[71,1130,971],{"class":85},[71,1132,974],{"class":81},[71,1134,560],{"class":85},[71,1136,979],{"class":99},[71,1138,982],{"class":650},[71,1140,100],{"class":99},[71,1142,113],{"class":85},[71,1144,989],{"class":81},[71,1146,560],{"class":85},[71,1148,994],{"class":728},[71,1150,223],{"class":85},[71,1152,1153,1155,1157,1159,1161,1163],{"class":73,"line":220},[71,1154,1001],{"class":92},[71,1156,96],{"class":85},[71,1158,1061],{"class":269},[71,1160,1006],{"class":81},[71,1162,532],{"class":85},[71,1164,1165],{"class":121},"      \u002F\u002F passamos o endereço\n",[71,1167,1168,1170,1172,1174,1176,1178,1180,1182,1184],{"class":73,"line":505},[71,1169,867],{"class":81},[71,1171,48],{"class":85},[71,1173,743],{"class":92},[71,1175,96],{"class":85},[71,1177,1006],{"class":81},[71,1179,48],{"class":85},[71,1181,935],{"class":81},[71,1183,532],{"class":85},[71,1185,1186],{"class":121}," \u002F\u002F 31 — mudou de verdade\n",[71,1188,1189],{"class":73,"line":883},[71,1190,223],{"class":85},[33,1192,1193,1194,1196,1197,1200,1201,1203,1204,1207],{},"Agora a função recebeu o endereço de ",[68,1195,1006],{},". Ao alterar ",[68,1198,1199],{},"u.Idade",", ela está mexendo no mesmo dado que existe no ",[68,1202,901],{},". Isso é ",[131,1205,1206],{},"pointer semantics",": você compartilha o acesso ao valor em vez de copiá-lo.",[235,1209,1210],{},[33,1211,1212,1213,1215,1216,1219,1220,1223],{},"Note que em ",[68,1214,1199],{}," não precisei escrever ",[68,1217,1218],{},"(*u).Idade",". Go faz esse \"de-referenciamento\" automaticamente para campos de struct acessados por ponteiro. É um ",[131,1221,1222],{},"syntactic sugar"," que deixa o código mais limpo.",[33,1225,1226],{},"Existem dois motivos principais para usar ponteiros:",[1228,1229,1230,1237],"ol",{},[1231,1232,1233,1236],"li",{},[37,1234,1235],{},"Mutação compartilhada",": quando a função precisa modificar o valor original.",[1231,1238,1239,1242],{},[37,1240,1241],{},"Evitar cópias caras",": quando a struct é grande, copiá-la a cada chamada custa memória e tempo.",[543,1244,1246],{"id":1245},"um-detalhe-que-muda-tudo-ponteiro-também-é-valor","Um detalhe que muda tudo: ponteiro também é valor",[33,1248,1249,1250,1253],{},"Aqui vai a sacada que costuma reorganizar o entendimento: em Go, tudo é passado por valor, sempre. Não existe \"passagem por referência\" como em algumas outras linguagens. Quando você passa um ponteiro, o que acontece é que o ",[131,1251,1252],{},"valor do ponteiro"," (ou seja, o endereço) é copiado.",[61,1255,1257],{"className":260,"code":1256,"language":262,"meta":66,"style":66},"u := User{Nome: \"João\"}\n\np := &u   \u002F\u002F p guarda o endereço de u\nq := p    \u002F\u002F q é uma CÓPIA do endereço, não \"referencia\" p\n",[68,1258,1259,1282,1286,1302],{"__ignoreMap":66},[71,1260,1261,1264,1266,1268,1270,1272,1274,1276,1278,1280],{"class":73,"line":74},[71,1262,1263],{"class":81},"u ",[71,1265,847],{"class":269},[71,1267,455],{"class":154},[71,1269,971],{"class":85},[71,1271,974],{"class":81},[71,1273,560],{"class":85},[71,1275,979],{"class":99},[71,1277,982],{"class":650},[71,1279,100],{"class":99},[71,1281,223],{"class":85},[71,1283,1284],{"class":73,"line":89},[71,1285,180],{"emptyLinePlaceholder":179},[71,1287,1288,1291,1293,1296,1299],{"class":73,"line":176},[71,1289,1290],{"class":81},"p ",[71,1292,847],{"class":269},[71,1294,1295],{"class":269}," &",[71,1297,1298],{"class":81},"u   ",[71,1300,1301],{"class":121},"\u002F\u002F p guarda o endereço de u\n",[71,1303,1304,1307,1309,1312],{"class":73,"line":183},[71,1305,1306],{"class":81},"q ",[71,1308,847],{"class":269},[71,1310,1311],{"class":81}," p    ",[71,1313,1314],{"class":121},"\u002F\u002F q é uma CÓPIA do endereço, não \"referencia\" p\n",[33,1316,1317,1320,1321,1323,1324,1326,1327,1329,1330,1332,1333,1335,1336,1338],{},[68,1318,1319],{},"q"," não aponta para ",[68,1322,33],{},". ",[68,1325,1319],{}," recebeu uma cópia do endereço que estava em ",[68,1328,33],{},". Os dois apontam para o mesmo ",[68,1331,345],{},", mas são dois ponteiros independentes. No fundo, ",[131,1334,1206],{}," é só ",[131,1337,776],{}," aplicada a um valor que por acaso é um endereço.",[33,1340,1341,1342,1344,1345,1348,1349,1352,1353,386,1356,386,1358,1361,1362,1364],{},"Isso também explica por que alguns tipos parecem se comportar de forma diferente. Quando você copia uma ",[68,1343,433],{}," ou um ",[68,1346,1347],{},"array",", copia o conteúdo inteiro: são valores ",[37,1350,1351],{},"autocontidos",". Já ",[68,1354,1355],{},"slice",[68,1357,674],{},[68,1359,1360],{},"channel"," e ",[68,1363,786],{}," carregam uma referência interna, então copiar um slice copia apenas o seu cabeçalho (ponteiro, tamanho e capacidade), não o array por baixo. É por isso que dois slices podem enxergar os mesmos dados mesmo sem você usar ponteiro explicitamente. Esse comportamento rende um artigo só pra ele, e é o que pretendo destrinchar em um próximo post.",[53,1366,1368],{"id":1367},"parte-4-como-escolher-entre-value-e-pointer-semantics","Parte 4: Como escolher entre value e pointer semantics",[33,1370,1371],{},"Ao longo dos anos, a comunidade e os mantenedores do Go consolidaram algumas diretrizes bem práticas (Effective Go, o Code Review Comments do Go Wiki, e gente como Dave Cheney e William Kennedy).",[33,1373,1374,1375,1378],{},"A regra mais importante vem do próprio time do Go: ",[37,1376,1377],{},"seja consistente",". A recomendação do Go Wiki é clara: se algum método de um tipo precisa de receiver por ponteiro, então normalmente todos deveriam usar ponteiro. Misturar value e pointer no mesmo tipo sem necessidade é fonte de bugs sutis.",[33,1380,1381],{},"Como ponto de partida:",[667,1383,1384,1389,1416,1421],{},[33,1385,1386],{},[37,1387,1388],{},"Use pointer semantics quando:",[1390,1391,1392,1399,1406],"ul",{},[1231,1393,1394,1395,1398],{},"A função precisa ",[37,1396,1397],{},"modificar"," o valor recebido.",[1231,1400,1401,1402,1405],{},"A struct é ",[37,1403,1404],{},"grande"," e a cópia seria custosa.",[1231,1407,1408,1409,1412,1413,1415],{},"O tipo representa algo que ",[37,1410,1411],{},"não deve ser copiado"," (como um ",[68,1414,559],{},", uma conexão, um buffer com estado).",[33,1417,1418],{},[37,1419,1420],{},"Use value semantics quando:",[1390,1422,1423,1434,1441],{},[1231,1424,1425,1426,1429,1430,1433],{},"O tipo é pequeno e representa um ",[37,1427,1428],{},"dado"," (um ponto, uma cor, um ",[68,1431,1432],{},"time.Time",").",[1231,1435,1436,1437,1440],{},"Você quer garantir ",[37,1438,1439],{},"imutabilidade"," e isolamento.",[1231,1442,1443],{},"Não há necessidade de modificar o original.",[33,1445,1446,1447,1449],{},"Um exemplo de tipo que idiomaticamente usa value semantics é ",[68,1448,1432],{},". Ele é passado por valor em toda a biblioteca padrão, mesmo sendo uma struct, porque representa um instante, um dado, não algo com estado mutável compartilhado.",[33,1451,1452,1453,386,1456,1459,1460,1462],{},"Já tipos como ",[68,1454,1455],{},"*sql.DB",[68,1457,1458],{},"*http.Request"," ou os que carregam um ",[68,1461,559],{}," usam pointer semantics, porque copiá-los seria errado ou perigoso.",[543,1464,1466],{"id":1465},"um-cuidado-importante-ponteiros-e-nil","Um cuidado importante: ponteiros e nil",[33,1468,1469,1470,1472,1473,1475],{},"Quando você adota pointer semantics, o zero value volta a aparecer e pode te passar uma rasteira. O zero value de um ponteiro é ",[68,1471,426],{},", e acessar um ponteiro ",[68,1474,426],{}," causa panic:",[61,1477,1479],{"className":260,"code":1478,"language":262,"meta":66,"style":66},"var u *User      \u002F\u002F nil\nfmt.Println(u.Nome) \u002F\u002F panic: invalid memory address\n",[68,1480,1481,1494],{"__ignoreMap":66},[71,1482,1483,1485,1487,1489,1491],{"class":73,"line":74},[71,1484,270],{"class":269},[71,1486,499],{"class":81},[71,1488,342],{"class":269},[71,1490,345],{"class":154},[71,1492,1493],{"class":121},"      \u002F\u002F nil\n",[71,1495,1496,1498,1500,1502,1504,1506,1508,1510,1512],{"class":73,"line":89},[71,1497,508],{"class":81},[71,1499,48],{"class":85},[71,1501,743],{"class":92},[71,1503,96],{"class":85},[71,1505,919],{"class":81},[71,1507,48],{"class":85},[71,1509,974],{"class":81},[71,1511,532],{"class":85},[71,1513,1514],{"class":121}," \u002F\u002F panic: invalid memory address\n",[33,1516,1517,1518,1521,1522,1525,1526,1528],{},"Repare no ciclo completo: foi justamente esse tipo de problema que os zero values resolveram para ",[131,1519,1520],{},"valores",", mas ele reaparece assim que você introduz ",[131,1523,1524],{},"ponteiros",". Por isso a escolha por pointer semantics não é gratuita, ela traz de volta a necessidade de pensar em ",[68,1527,426],{},". É mais um argumento a favor de preferir value semantics quando você não tem um motivo claro para o contrário.",[53,1530,1532],{"id":1531},"juntando-tudo-o-caminho-mental","Juntando tudo: o caminho mental",[33,1534,1535],{},"Se eu tivesse que resumir o raciocínio em uma sequência de perguntas na hora de escrever código Go, seria assim:",[1228,1537,1538,1544,1550,1556,1562],{},[1231,1539,1540,1543],{},[37,1541,1542],{},"Qual o estado inicial natural do meu tipo?"," Se o zero value já for utilizável, aproveite, menos inicialização, menos código.",[1231,1545,1546,1549],{},[37,1547,1548],{},"Essa função precisa alterar o valor original?"," Se sim, ponteiro. Se não, comece pensando em valor.",[1231,1551,1552,1555],{},[37,1553,1554],{},"O valor é grande ou não pode ser copiado?"," Se sim, ponteiro, mesmo sem mutação.",[1231,1557,1558,1561],{},[37,1559,1560],{},"Estou sendo consistente com o resto do tipo?"," Se um método precisa de ponteiro, normalmente todos os outros também deveriam usar ponteiro.",[1231,1563,1564,1570],{},[37,1565,1566,1567,1569],{},"Ao usar ponteiros, tratei o caso ",[68,1568,426],{},"?"," O zero value voltou; não deixe ele te pegar.",[33,1572,1573],{},"Zero values e semântica de passagem não são tópicos isolados: são duas faces da mesma ideia de que, em Go, o estado de um valor deve ser sempre previsível. Value semantics preserva o isolamento dos dados: cada parte do código trabalha com sua própria cópia. Pointer semantics abre mão desse isolamento de propósito, para permitir compartilhamento de estado entre diferentes partes do código, e é justamente por isso que exige mais cuidado.",[53,1575,1577],{"id":1576},"referências","Referências",[1390,1579,1580,1590,1605,1613,1621,1629,1637],{},[1231,1581,1582,1589],{},[1583,1584,1588],"a",{"href":1585,"rel":1586},"https:\u002F\u002Fgo.dev\u002Fref\u002Fspec#The_zero_value",[1587],"nofollow","The Go Programming Language Specification — The zero value"," — definição oficial de zero values na spec da linguagem.",[1231,1591,1592,1597,1598,386,1601,1604],{},[1583,1593,1596],{"href":1594,"rel":1595},"https:\u002F\u002Fgo.dev\u002Fdoc\u002Feffective_go#data",[1587],"Effective Go — Data \u002F Allocation"," — como o Go trata inicialização, ",[68,1599,1600],{},"new",[68,1602,1603],{},"make"," e o padrão do zero value útil.",[1231,1606,1607,1612],{},[1583,1608,1611],{"href":1609,"rel":1610},"https:\u002F\u002Fgo.dev\u002Fblog\u002Flaws-of-reflection",[1587],"Go Blog — The Laws of Reflection"," — contexto sobre valores, tipos e como Go os representa internamente.",[1231,1614,1615,1620],{},[1583,1616,1619],{"href":1617,"rel":1618},"https:\u002F\u002Fwww.ardanlabs.com\u002Fblog\u002F2017\u002F06\u002Fdesign-philosophy-on-data-and-semantics.html",[1587],"Ardan Labs — Value and Pointer Semantics (William Kennedy)"," — a referência mais citada sobre a filosofia de escolher entre value e pointer semantics.",[1231,1622,1623,1628],{},[1583,1624,1627],{"href":1625,"rel":1626},"https:\u002F\u002Fgo.dev\u002Fwiki\u002FCodeReviewComments#receiver-type",[1587],"Go Wiki — Code Review Comments: Receiver Type"," — diretrizes oficiais sobre quando usar receivers por valor ou por ponteiro.",[1231,1630,1631,1636],{},[1583,1632,1635],{"href":1633,"rel":1634},"https:\u002F\u002Fdave.cheney.net\u002F2016\u002F03\u002F19\u002Fshould-methods-be-declared-on-t-or-t",[1587],"Dave Cheney — Should methods be declared on T or *T"," — discussão aprofundada sobre consistência de semântica em métodos.",[1231,1638,1639,1644],{},[1583,1640,1643],{"href":1641,"rel":1642},"https:\u002F\u002Fgo.dev\u002Ftour\u002Fmoretypes\u002F1",[1587],"A Tour of Go — Pointers"," — introdução interativa e oficial a ponteiros.",[1646,1647,1648],"style",{},"html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .swQdS, html code.shiki .swQdS{--shiki-light:#E53935;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .s_bVq, html code.shiki .s_bVq{--shiki-light:#9C3EDA;--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":66,"searchDepth":89,"depth":89,"links":1650},[1651,1652,1655,1656,1659,1662,1663],{"id":55,"depth":89,"text":56},{"id":253,"depth":89,"text":254,"children":1653},[1654],{"id":545,"depth":176,"text":546},{"id":765,"depth":89,"text":766},{"id":1043,"depth":89,"text":1044,"children":1657},[1658],{"id":1245,"depth":176,"text":1246},{"id":1367,"depth":89,"text":1368,"children":1660},[1661],{"id":1465,"depth":176,"text":1466},{"id":1531,"depth":89,"text":1532},{"id":1576,"depth":89,"text":1577},"2026-04-12","Entenda zero values, value semantics e pointer semantics em Go: o que são, quando copiar por valor ou passar por ponteiro e como escolher, com exemplos práticos.","md","https:\u002F\u002Fencrypted-tbn0.gstatic.com\u002Fimages?q=tbn:ANd9GcQvXqKsNKgbxpINxN06GeyY8UPggpH6RUlMZtcJwYptYOPdaD3k4-nHOzd5&s=10",{},10,{"title":18,"description":1665},"5X4sk4fKVmkMi255j5zzegR_u_395FzojlcSobfH-1Q",1786023409655]