[{"data":1,"prerenderedAt":3869},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Farrays-e-slices-em-go-capacidade-crescimento-e-append":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":10,"author":28,"body":29,"date":3861,"description":3862,"extension":3863,"image":3864,"meta":3865,"minRead":3866,"navigation":356,"path":11,"seo":3867,"stem":12,"tags":28,"updatedAt":28,"__hash__":3868},"blog\u002Fblog\u002Farrays-e-slices-em-go-capacidade-crescimento-e-append.md",null,{"type":30,"value":31,"toc":3840},"minimark",[32,42,45,155,161,210,218,225,236,242,257,262,268,275,298,309,315,333,336,339,517,520,523,654,660,663,666,826,829,835,844,860,863,962,966,969,992,999,1002,1178,1198,1204,1210,1226,1235,1238,1241,1368,1386,1392,1399,1405,1411,1414,1421,1439,1444,1452,1557,1575,1579,1589,1606,1689,1695,1699,1706,1729,1732,1742,1940,1943,1960,1963,1967,1977,1986,1992,2006,2011,2066,2084,2101,2105,2111,2182,2191,2211,2242,2254,2260,2264,2267,2335,2358,2373,2379,2487,2497,2548,2551,2631,2637,2653,2657,2663,2791,2797,2803,2810,2909,2913,2916,2919,2933,2936,3041,3044,3050,3053,3065,3069,3095,3111,3117,3133,3140,3247,3275,3283,3377,3384,3400,3418,3422,3425,3532,3549,3553,3556,3607,3618,3628,3632,3836],[33,34,35,36,41],"p",{},"No artigo sobre ",[37,38,40],"a",{"href":39},"\u002Fgo-zero-values-e-value-semantics-vs-pointer-semantics","zero values e pointer semantics"," eu comentei de passagem que copiar um slice copia só o seu cabeçalho, não o array por baixo, e que aquilo rendia um artigo inteiro. É este aqui.",[33,43,44],{},"Vamos começar pelo fim, com um bug real. Imagine um router HTTP em que cada grupo de rotas herda os middlewares do grupo pai:",[46,47,52],"pre",{"className":48,"code":49,"language":50,"meta":51,"style":51},"language-go shiki shiki-themes material-theme-lighter github-light github-dark","func (r *Router) Group(m Middleware) *Router {\n    return &Router{middlewares: append(r.middlewares, m)}\n}\n","go","",[53,54,55,105,149],"code",{"__ignoreMap":51},[56,57,60,64,68,72,75,79,82,86,89,92,95,97,100,102],"span",{"class":58,"line":59},"line",1,[56,61,63],{"class":62},"smGrS","func",[56,65,67],{"class":66},"sP7_E"," (",[56,69,71],{"class":70},"s99_P","r ",[56,73,74],{"class":62},"*",[56,76,78],{"class":77},"sbgvK","Router",[56,80,81],{"class":66},")",[56,83,85],{"class":84},"sGLFI"," Group",[56,87,88],{"class":66},"(",[56,90,91],{"class":70},"m",[56,93,94],{"class":77}," Middleware",[56,96,81],{"class":66},[56,98,99],{"class":62}," *",[56,101,78],{"class":77},[56,103,104],{"class":66}," {\n",[56,106,108,112,115,117,120,124,127,130,132,135,138,140,143,146],{"class":58,"line":107},2,[56,109,111],{"class":110},"sVHd0","    return",[56,113,114],{"class":62}," &",[56,116,78],{"class":77},[56,118,119],{"class":66},"{",[56,121,123],{"class":122},"su5hD","middlewares",[56,125,126],{"class":66},":",[56,128,129],{"class":84}," append",[56,131,88],{"class":66},[56,133,134],{"class":122},"r",[56,136,137],{"class":66},".",[56,139,123],{"class":122},[56,141,142],{"class":66},",",[56,144,145],{"class":122}," m",[56,147,148],{"class":66},")}\n",[56,150,152],{"class":58,"line":151},3,[56,153,154],{"class":66},"}\n",[33,156,157,158,160],{},"A função tem uma linha, não tem ponteiro solto, não tem concorrência, e devolve um ",[53,159,78],{}," novo em vez de mutar o antigo. Parece o tipo de código que não tem como dar errado. Agora o uso:",[46,162,164],{"className":48,"code":163,"language":50,"meta":51,"style":51},"admin := root.Group(requireAdmin)\npublic := root.Group(rateLimit)\n",[53,165,166,190],{"__ignoreMap":51},[56,167,168,171,174,177,179,182,184,187],{"class":58,"line":59},[56,169,170],{"class":122},"admin ",[56,172,173],{"class":62},":=",[56,175,176],{"class":122}," root",[56,178,137],{"class":66},[56,180,181],{"class":84},"Group",[56,183,88],{"class":66},[56,185,186],{"class":122},"requireAdmin",[56,188,189],{"class":66},")\n",[56,191,192,195,197,199,201,203,205,208],{"class":58,"line":107},[56,193,194],{"class":122},"public ",[56,196,173],{"class":62},[56,198,176],{"class":122},[56,200,137],{"class":66},[56,202,181],{"class":84},[56,204,88],{"class":66},[56,206,207],{"class":122},"rateLimit",[56,209,189],{"class":66},[46,211,216],{"className":212,"code":214,"language":215,"meta":51},[213],"language-text","root: len=3 cap=4 [logging recover requestID]\n\nadmin : [logging recover requestID rateLimit]\npublic: [logging recover requestID rateLimit]\n","text",[53,217,214],{"__ignoreMap":51},[33,219,220,221,224],{},"O router de admin ficou sem o middleware de autenticação. Ninguém sobrescreveu nada de propósito, e o código está sintaticamente correto. O que aconteceu é que os dois ",[53,222,223],{},"append"," escreveram na mesma posição do mesmo array, e o segundo passou por cima do primeiro.",[33,226,227,228,231,232,235],{},"Repare no ",[53,229,230],{},"cap=4"," com ",[53,233,234],{},"len=3",". Se fossem iguais, o bug não aconteceria. Ou seja: esse código funciona ou não dependendo de quantos middlewares o pai tinha. Esse é o tipo de bug que passa em teste, passa em code review e aparece em produção seis meses depois, quando alguém adiciona um middleware a mais.",[33,237,238,239,241],{},"A proposta deste artigo é destrinchar exatamente isso: primeiro a diferença entre array e slice, depois o que é capacidade e por que ela não é um detalhe, como o ",[53,240,223],{}," faz o slice crescer, e por fim como dois slices acabam enxergando a mesma memória — e o que fazer a respeito.",[243,244,245],"note",{},[33,246,247,248,252,253,256],{},"Tudo aqui foi verificado com ",[249,250,251],"strong",{},"Go 1.26"," no ",[53,254,255],{},"gc"," (o compilador oficial). Números concretos de capacidade são detalhes de implementação e já mudaram entre versões; existe uma seção sobre isso mais adiante.",[258,259,261],"h2",{"id":260},"duas-coisas-diferentes-com-nomes-parecidos","Duas coisas diferentes com nomes parecidos",[33,263,264,265,267],{},"Antes de falar do ",[53,266,223],{},", vale separar dois tipos que a sintaxe faz parecer irmãos e que não são a mesma coisa.",[33,269,270,271,274],{},"Um ",[249,272,273],{},"array"," é um valor autocontido, e o tamanho faz parte do tipo. A spec é direta:",[276,277,278,285],"blockquote",{},[33,279,280,281,284],{},"\"O tamanho faz parte do tipo do array; ele precisa ser avaliado como uma constante não negativa representável por um valor do tipo ",[53,282,283],{},"int",".\"",[33,286,287,288],{},"— ",[37,289,293,294],{"href":290,"rel":291},"https:\u002F\u002Fgo.dev\u002Fref\u002Fspec#Array_types",[292],"nofollow","The Go Programming Language Specification, ",[295,296,297],"em",{},"Array types",[33,299,300,301,304,305,308],{},"Isso tem uma consequência que assusta quem vem de C: ",[53,302,303],{},"[3]int"," e ",[53,306,307],{},"[4]int"," são tipos diferentes. Não dá para passar um onde se espera o outro, e não dá nem para compará-los.",[33,310,270,311,314],{},[249,312,313],{},"slice",", por outro lado, não guarda os dados. Ele descreve um pedaço de um array que mora em outro lugar:",[276,316,317,324],{},[33,318,319,320,323],{},"\"Um slice é um descritor para um segmento contíguo de um ",[295,321,322],{},"array subjacente"," e dá acesso a uma sequência numerada de elementos daquele array. (...) Um slice, uma vez inicializado, está sempre associado a um array subjacente que guarda seus elementos. Um slice, portanto, compartilha armazenamento com seu array e com outros slices do mesmo array; por outro lado, arrays distintos sempre representam armazenamentos distintos.\"",[33,325,287,326],{},[37,327,293,330],{"href":328,"rel":329},"https:\u002F\u002Fgo.dev\u002Fref\u002Fspec#Slice_types",[292],[295,331,332],{},"Slice types",[33,334,335],{},"Essa última frase é o artigo inteiro em uma linha. Guarde ela.",[33,337,338],{},"A diferença aparece na hora de medir:",[46,340,342],{"className":48,"code":341,"language":50,"meta":51,"style":51},"package main\n\nimport (\n    \"fmt\"\n    \"unsafe\"\n)\n\nfunc main() {\n    var arr [1000]int\n    var sl []int\n\n    fmt.Println(unsafe.Sizeof(arr)) \u002F\u002F 8000\n    fmt.Println(unsafe.Sizeof(sl))  \u002F\u002F 24\n}\n",[53,343,344,352,358,366,379,389,394,399,412,435,448,453,485,512],{"__ignoreMap":51},[56,345,346,349],{"class":58,"line":59},[56,347,348],{"class":62},"package",[56,350,351],{"class":77}," main\n",[56,353,354],{"class":58,"line":107},[56,355,357],{"emptyLinePlaceholder":356},true,"\n",[56,359,360,363],{"class":58,"line":151},[56,361,362],{"class":110},"import",[56,364,365],{"class":66}," (\n",[56,367,369,373,376],{"class":58,"line":368},4,[56,370,372],{"class":371},"sjJ54","    \"",[56,374,375],{"class":77},"fmt",[56,377,378],{"class":371},"\"\n",[56,380,382,384,387],{"class":58,"line":381},5,[56,383,372],{"class":371},[56,385,386],{"class":77},"unsafe",[56,388,378],{"class":371},[56,390,392],{"class":58,"line":391},6,[56,393,189],{"class":66},[56,395,397],{"class":58,"line":396},7,[56,398,357],{"emptyLinePlaceholder":356},[56,400,402,404,407,410],{"class":58,"line":401},8,[56,403,63],{"class":62},[56,405,406],{"class":84}," main",[56,408,409],{"class":66},"()",[56,411,104],{"class":66},[56,413,415,418,421,424,428,431],{"class":58,"line":414},9,[56,416,417],{"class":62},"    var",[56,419,420],{"class":122}," arr ",[56,422,423],{"class":66},"[",[56,425,427],{"class":426},"srdBf","1000",[56,429,430],{"class":66},"]",[56,432,434],{"class":433},"sbsja","int\n",[56,436,438,440,443,446],{"class":58,"line":437},10,[56,439,417],{"class":62},[56,441,442],{"class":122}," sl ",[56,444,445],{"class":66},"[]",[56,447,434],{"class":433},[56,449,451],{"class":58,"line":450},11,[56,452,357],{"emptyLinePlaceholder":356},[56,454,456,459,461,464,466,468,470,473,475,478,481],{"class":58,"line":455},12,[56,457,458],{"class":122},"    fmt",[56,460,137],{"class":66},[56,462,463],{"class":84},"Println",[56,465,88],{"class":66},[56,467,386],{"class":122},[56,469,137],{"class":66},[56,471,472],{"class":84},"Sizeof",[56,474,88],{"class":66},[56,476,477],{"class":122},"arr",[56,479,480],{"class":66},"))",[56,482,484],{"class":483},"sutJx"," \u002F\u002F 8000\n",[56,486,488,490,492,494,496,498,500,502,504,507,509],{"class":58,"line":487},13,[56,489,458],{"class":122},[56,491,137],{"class":66},[56,493,463],{"class":84},[56,495,88],{"class":66},[56,497,386],{"class":122},[56,499,137],{"class":66},[56,501,472],{"class":84},[56,503,88],{"class":66},[56,505,506],{"class":122},"sl",[56,508,480],{"class":66},[56,510,511],{"class":483},"  \u002F\u002F 24\n",[56,513,515],{"class":58,"line":514},14,[56,516,154],{"class":66},[33,518,519],{},"O array ocupa os 8000 bytes que ele promete. O slice ocupa 24 bytes em qualquer plataforma de 64 bits, independentemente de descrever três elementos ou três milhões, porque ele é só um ponteiro e dois inteiros.",[33,521,522],{},"E isso não é curiosidade acadêmica: array é valor, então passar um array para uma função copia o array inteiro.",[46,524,526],{"className":48,"code":525,"language":50,"meta":51,"style":51},"package arrbench\n\ntype Buffer [4096]byte\n\n\u002F\u002Fgo:noinline\nfunc firstArray(b Buffer) byte { return b[0] } \u002F\u002F copia 4 KiB para ler 1 byte\n\n\u002F\u002Fgo:noinline\nfunc firstSlice(b []byte) byte { return b[0] } \u002F\u002F copia 24 bytes de cabeçalho\n",[53,527,528,535,539,558,562,567,608,612,616],{"__ignoreMap":51},[56,529,530,532],{"class":58,"line":59},[56,531,348],{"class":62},[56,533,534],{"class":77}," arrbench\n",[56,536,537],{"class":58,"line":107},[56,538,357],{"emptyLinePlaceholder":356},[56,540,541,544,547,550,553,555],{"class":58,"line":151},[56,542,543],{"class":62},"type",[56,545,546],{"class":77}," Buffer",[56,548,549],{"class":66}," [",[56,551,552],{"class":426},"4096",[56,554,430],{"class":66},[56,556,557],{"class":433},"byte\n",[56,559,560],{"class":58,"line":368},[56,561,357],{"emptyLinePlaceholder":356},[56,563,564],{"class":58,"line":381},[56,565,566],{"class":483},"\u002F\u002Fgo:noinline\n",[56,568,569,571,574,576,579,581,583,586,589,592,595,597,600,602,605],{"class":58,"line":391},[56,570,63],{"class":62},[56,572,573],{"class":84}," firstArray",[56,575,88],{"class":66},[56,577,578],{"class":70},"b",[56,580,546],{"class":77},[56,582,81],{"class":66},[56,584,585],{"class":433}," byte",[56,587,588],{"class":66}," {",[56,590,591],{"class":110}," return",[56,593,594],{"class":122}," b",[56,596,423],{"class":66},[56,598,599],{"class":426},"0",[56,601,430],{"class":66},[56,603,604],{"class":66}," }",[56,606,607],{"class":483}," \u002F\u002F copia 4 KiB para ler 1 byte\n",[56,609,610],{"class":58,"line":396},[56,611,357],{"emptyLinePlaceholder":356},[56,613,614],{"class":58,"line":401},[56,615,566],{"class":483},[56,617,618,620,623,625,627,630,633,635,637,639,641,643,645,647,649,651],{"class":58,"line":414},[56,619,63],{"class":62},[56,621,622],{"class":84}," firstSlice",[56,624,88],{"class":66},[56,626,578],{"class":70},[56,628,629],{"class":66}," []",[56,631,632],{"class":433},"byte",[56,634,81],{"class":66},[56,636,585],{"class":433},[56,638,588],{"class":66},[56,640,591],{"class":110},[56,642,594],{"class":122},[56,644,423],{"class":66},[56,646,599],{"class":426},[56,648,430],{"class":66},[56,650,604],{"class":66},[56,652,653],{"class":483}," \u002F\u002F copia 24 bytes de cabeçalho\n",[46,655,658],{"className":656,"code":657,"language":215,"meta":51},[213],"BenchmarkArrayParam-8    23730294    48.16  ns\u002Fop    0 B\u002Fop    0 allocs\u002Fop\nBenchmarkSliceParam-8   927475783     1.375 ns\u002Fop    0 B\u002Fop    0 allocs\u002Fop\n",[53,659,657],{"__ignoreMap":51},[33,661,662],{},"Os dois corpos são idênticos. A diferença de 47 nanossegundos é a cópia dos 4 KiB que acontece antes de a função começar. Não há alocação em nenhum dos dois casos — o custo é puramente de cópia, e é por isso que arrays grandes quase nunca aparecem como parâmetro em código Go.",[33,664,665],{},"Em compensação, ser um valor autocontido dá ao array duas capacidades que o slice não tem:",[46,667,669],{"className":48,"code":668,"language":50,"meta":51,"style":51},"a := [3]int{1, 2, 3}\nb := [3]int{1, 2, 3}\nfmt.Println(a == b) \u002F\u002F true\n\nroutes := map[[2]string]int{\n    {\"GET\", \"\u002Fusers\"}: 1, \u002F\u002F array como chave de map\n}\n",[53,670,671,704,733,755,759,787,822],{"__ignoreMap":51},[56,672,673,676,678,680,683,685,687,689,692,694,697,699,702],{"class":58,"line":59},[56,674,675],{"class":122},"a ",[56,677,173],{"class":62},[56,679,549],{"class":66},[56,681,682],{"class":426},"3",[56,684,430],{"class":66},[56,686,283],{"class":433},[56,688,119],{"class":66},[56,690,691],{"class":426},"1",[56,693,142],{"class":66},[56,695,696],{"class":426}," 2",[56,698,142],{"class":66},[56,700,701],{"class":426}," 3",[56,703,154],{"class":66},[56,705,706,709,711,713,715,717,719,721,723,725,727,729,731],{"class":58,"line":107},[56,707,708],{"class":122},"b ",[56,710,173],{"class":62},[56,712,549],{"class":66},[56,714,682],{"class":426},[56,716,430],{"class":66},[56,718,283],{"class":433},[56,720,119],{"class":66},[56,722,691],{"class":426},[56,724,142],{"class":66},[56,726,696],{"class":426},[56,728,142],{"class":66},[56,730,701],{"class":426},[56,732,154],{"class":66},[56,734,735,737,739,741,743,745,748,750,752],{"class":58,"line":151},[56,736,375],{"class":122},[56,738,137],{"class":66},[56,740,463],{"class":84},[56,742,88],{"class":66},[56,744,675],{"class":122},[56,746,747],{"class":62},"==",[56,749,594],{"class":122},[56,751,81],{"class":66},[56,753,754],{"class":483}," \u002F\u002F true\n",[56,756,757],{"class":58,"line":368},[56,758,357],{"emptyLinePlaceholder":356},[56,760,761,764,766,769,772,775,777,780,782,784],{"class":58,"line":381},[56,762,763],{"class":122},"routes ",[56,765,173],{"class":62},[56,767,768],{"class":62}," map",[56,770,771],{"class":66},"[[",[56,773,774],{"class":426},"2",[56,776,430],{"class":66},[56,778,779],{"class":433},"string",[56,781,430],{"class":66},[56,783,283],{"class":433},[56,785,786],{"class":66},"{\n",[56,788,789,792,795,799,801,803,806,809,811,814,817,819],{"class":58,"line":391},[56,790,791],{"class":66},"    {",[56,793,794],{"class":371},"\"",[56,796,798],{"class":797},"s_sjI","GET",[56,800,794],{"class":371},[56,802,142],{"class":66},[56,804,805],{"class":371}," \"",[56,807,808],{"class":797},"\u002Fusers",[56,810,794],{"class":371},[56,812,813],{"class":66},"}:",[56,815,816],{"class":426}," 1",[56,818,142],{"class":66},[56,820,821],{"class":483}," \u002F\u002F array como chave de map\n",[56,823,824],{"class":58,"line":396},[56,825,154],{"class":66},[33,827,828],{},"Arrays são comparáveis se o tipo dos elementos for comparável, e por isso servem como chave de map. Slices não:",[46,830,833],{"className":831,"code":832,"language":215,"meta":51},[213],"invalid operation: a == b (slice can only be compared to nil)\n",[53,834,832],{"__ignoreMap":51},[33,836,837,838,840,841,137],{},"O motivo é o mesmo compartilhamento de armazenamento citado na spec: dois slices podem apontar para o mesmo array, ou para arrays diferentes com o mesmo conteúdo, e não existe uma resposta óbvia para o que ",[53,839,747],{}," deveria significar aí. Para comparar conteúdo existe ",[53,842,843],{},"slices.Equal",[845,846,847,854],"tip",{},[33,848,849,850,853],{},"A restrição é contagiosa. Uma struct só é comparável se todos os campos forem comparáveis, então basta um campo ",[53,851,852],{},"[]string"," para o tipo inteiro deixar de servir como chave de map:",[46,855,858],{"className":856,"code":857,"language":215,"meta":51},[213],"invalid operation: x == y (struct containing []string cannot be compared)\n",[53,859,857],{"__ignoreMap":51},[33,861,862],{},"Resumindo a diferença:",[864,865,866,887],"table",{},[867,868,869],"thead",{},[870,871,872,875,881],"tr",{},[873,874],"th",{},[873,876,877,878],{},"Array ",[53,879,880],{},"[N]T",[873,882,883,884],{},"Slice ",[53,885,886],{},"[]T",[888,889,890,902,919,930,950],"tbody",{},[870,891,892,896,899],{},[893,894,895],"td",{},"Tamanho",[893,897,898],{},"fixo, faz parte do tipo",[893,900,901],{},"variável em tempo de execução",[870,903,904,907,910],{},[893,905,906],{},"O que a variável guarda",[893,908,909],{},"os elementos",[893,911,912,913,304,916],{},"ponteiro, ",[53,914,915],{},"len",[53,917,918],{},"cap",[870,920,921,924,927],{},[893,922,923],{},"Custo de copiar",[893,925,926],{},"proporcional ao tamanho",[893,928,929],{},"24 bytes (64 bits)",[870,931,932,937,944],{},[893,933,934,935],{},"Comparável com ",[53,936,747],{},[893,938,939,940,943],{},"sim, se ",[53,941,942],{},"T"," for comparável",[893,945,946,947],{},"só contra ",[53,948,949],{},"nil",[870,951,952,955,958],{},[893,953,954],{},"Zero value",[893,956,957],{},"todos os elementos zerados",[893,959,960],{},[53,961,949],{},[258,963,965],{"id":964},"parte-1-o-cabeçalho-de-três-palavras","Parte 1: o cabeçalho de três palavras",[33,967,968],{},"Aqueles 24 bytes são três palavras: um ponteiro para o início do segmento, o comprimento e a capacidade. O blog oficial descreve o slice assim:",[276,970,971,982],{},[33,972,973,974,977,978,981],{},"\"Uma slice é uma estrutura de dados que descreve uma seção contígua de um array guardado separadamente da própria variável slice. ",[295,975,976],{},"Uma slice não é um array",". Uma slice ",[295,979,980],{},"descreve"," um pedaço de um array.\"",[33,983,287,984],{},[37,985,988,989],{"href":986,"rel":987},"https:\u002F\u002Fgo.dev\u002Fblog\u002Fslices",[292],"Go Blog, ",[295,990,991],{},"Arrays, slices (and strings): The mechanics of 'append'",[33,993,994,995,998],{},"E aqui está o ponto que reorganiza o entendimento, e que é a continuação direta do artigo anterior: ",[249,996,997],{},"o cabeçalho também é um valor",". Quando você passa um slice para uma função, o cabeçalho é copiado. Os dois cabeçalhos apontam para o mesmo array, mas são cabeçalhos independentes.",[33,1000,1001],{},"Isso explica um comportamento que parece contraditório:",[46,1003,1005],{"className":48,"code":1004,"language":50,"meta":51,"style":51},"package main\n\nimport \"fmt\"\n\nfunc mutate(s []int) {\n    s[0] = 99            \u002F\u002F o chamador vê\n    s = append(s, 4)     \u002F\u002F o chamador NÃO vê\n}\n\nfunc main() {\n    s := []int{1, 2, 3}\n    mutate(s)\n    fmt.Println(s, len(s)) \u002F\u002F [99 2 3] 3\n}\n",[53,1006,1007,1013,1017,1027,1031,1051,1071,1095,1099,1103,1113,1137,1148,1174],{"__ignoreMap":51},[56,1008,1009,1011],{"class":58,"line":59},[56,1010,348],{"class":62},[56,1012,351],{"class":77},[56,1014,1015],{"class":58,"line":107},[56,1016,357],{"emptyLinePlaceholder":356},[56,1018,1019,1021,1023,1025],{"class":58,"line":151},[56,1020,362],{"class":110},[56,1022,805],{"class":371},[56,1024,375],{"class":77},[56,1026,378],{"class":371},[56,1028,1029],{"class":58,"line":368},[56,1030,357],{"emptyLinePlaceholder":356},[56,1032,1033,1035,1038,1040,1043,1045,1047,1049],{"class":58,"line":381},[56,1034,63],{"class":62},[56,1036,1037],{"class":84}," mutate",[56,1039,88],{"class":66},[56,1041,1042],{"class":70},"s",[56,1044,629],{"class":66},[56,1046,283],{"class":433},[56,1048,81],{"class":66},[56,1050,104],{"class":66},[56,1052,1053,1056,1058,1060,1062,1065,1068],{"class":58,"line":391},[56,1054,1055],{"class":122},"    s",[56,1057,423],{"class":66},[56,1059,599],{"class":426},[56,1061,430],{"class":66},[56,1063,1064],{"class":62}," =",[56,1066,1067],{"class":426}," 99",[56,1069,1070],{"class":483},"            \u002F\u002F o chamador vê\n",[56,1072,1073,1076,1079,1081,1083,1085,1087,1090,1092],{"class":58,"line":396},[56,1074,1075],{"class":122},"    s ",[56,1077,1078],{"class":62},"=",[56,1080,129],{"class":84},[56,1082,88],{"class":66},[56,1084,1042],{"class":122},[56,1086,142],{"class":66},[56,1088,1089],{"class":426}," 4",[56,1091,81],{"class":66},[56,1093,1094],{"class":483},"     \u002F\u002F o chamador NÃO vê\n",[56,1096,1097],{"class":58,"line":401},[56,1098,154],{"class":66},[56,1100,1101],{"class":58,"line":414},[56,1102,357],{"emptyLinePlaceholder":356},[56,1104,1105,1107,1109,1111],{"class":58,"line":437},[56,1106,63],{"class":62},[56,1108,406],{"class":84},[56,1110,409],{"class":66},[56,1112,104],{"class":66},[56,1114,1115,1117,1119,1121,1123,1125,1127,1129,1131,1133,1135],{"class":58,"line":450},[56,1116,1075],{"class":122},[56,1118,173],{"class":62},[56,1120,629],{"class":66},[56,1122,283],{"class":433},[56,1124,119],{"class":66},[56,1126,691],{"class":426},[56,1128,142],{"class":66},[56,1130,696],{"class":426},[56,1132,142],{"class":66},[56,1134,701],{"class":426},[56,1136,154],{"class":66},[56,1138,1139,1142,1144,1146],{"class":58,"line":455},[56,1140,1141],{"class":84},"    mutate",[56,1143,88],{"class":66},[56,1145,1042],{"class":122},[56,1147,189],{"class":66},[56,1149,1150,1152,1154,1156,1158,1160,1162,1165,1167,1169,1171],{"class":58,"line":487},[56,1151,458],{"class":122},[56,1153,137],{"class":66},[56,1155,463],{"class":84},[56,1157,88],{"class":66},[56,1159,1042],{"class":122},[56,1161,142],{"class":66},[56,1163,1164],{"class":84}," len",[56,1166,88],{"class":66},[56,1168,1042],{"class":122},[56,1170,480],{"class":66},[56,1172,1173],{"class":483}," \u002F\u002F [99 2 3] 3\n",[56,1175,1176],{"class":58,"line":514},[56,1177,154],{"class":66},[33,1179,1180,1181,1184,1185,1187,1188,1190,1191,1194,1195,1197],{},"As duas linhas parecem mexer no mesmo slice, e só uma tem efeito lá fora. ",[53,1182,1183],{},"s[0] = 99"," escreve no array, que é compartilhado. Já ",[53,1186,223],{}," devolve um cabeçalho novo, com ",[53,1189,915],{}," igual a 4, e atribui esse cabeçalho à cópia local. O ",[53,1192,1193],{},"main"," continua com o cabeçalho antigo, de ",[53,1196,915],{}," 3.",[33,1199,1200,1201,1203],{},"É exatamente por isso que ",[53,1202,223],{}," devolve um valor em vez de mutar o slice no lugar, e por que ignorar esse retorno não é um estilo alternativo, é um erro de compilação:",[46,1205,1208],{"className":1206,"code":1207,"language":215,"meta":51},[213],"append(s, 2) (value of type []int) is not used\n",[53,1209,1207],{"__ignoreMap":51},[243,1211,1212],{},[33,1213,1214,1215,1218,1219,1221,1222,1225],{},"Vale reforçar a assimetria, porque ela é a origem de metade da confusão com slices: ",[249,1216,1217],{},"os elementos são compartilhados, o cabeçalho não é."," Passar um slice adiante permite que a função altere seus dados, mas não permite que ela altere o seu ",[53,1220,915],{},". Se você precisa disso, devolva o slice (o que é idiomático) ou receba um ",[53,1223,1224],{},"*[]T"," (o que raramente é).",[258,1227,1229,1230,1232,1233],{"id":1228},"parte-2-len-não-é-cap","Parte 2: ",[53,1231,915],{}," não é ",[53,1234,918],{},[33,1236,1237],{},"O comprimento é quantos elementos o slice tem. A capacidade é quantos ele poderia ter sem trocar de array — é a distância entre o começo do slice e o fim do array subjacente.",[33,1239,1240],{},"A distinção parece burocrática até você escrever, quase sempre sem perceber, esta função:",[46,1242,1244],{"className":48,"code":1243,"language":50,"meta":51,"style":51},"\u002F\u002F Errado: make com len, e não com cap.\nfunc orderIDs(orders []Order) []int64 {\n    out := make([]int64, len(orders))\n    for _, o := range orders {\n        out = append(out, o.ID)\n    }\n    return out\n}\n",[53,1245,1246,1251,1277,1303,1326,1352,1357,1364],{"__ignoreMap":51},[56,1247,1248],{"class":58,"line":59},[56,1249,1250],{"class":483},"\u002F\u002F Errado: make com len, e não com cap.\n",[56,1252,1253,1255,1258,1260,1263,1265,1268,1270,1272,1275],{"class":58,"line":107},[56,1254,63],{"class":62},[56,1256,1257],{"class":84}," orderIDs",[56,1259,88],{"class":66},[56,1261,1262],{"class":70},"orders",[56,1264,629],{"class":66},[56,1266,1267],{"class":77},"Order",[56,1269,81],{"class":66},[56,1271,629],{"class":66},[56,1273,1274],{"class":433},"int64",[56,1276,104],{"class":66},[56,1278,1279,1282,1284,1287,1290,1292,1294,1296,1298,1300],{"class":58,"line":151},[56,1280,1281],{"class":122},"    out ",[56,1283,173],{"class":62},[56,1285,1286],{"class":84}," make",[56,1288,1289],{"class":66},"([]",[56,1291,1274],{"class":433},[56,1293,142],{"class":66},[56,1295,1164],{"class":84},[56,1297,88],{"class":66},[56,1299,1262],{"class":122},[56,1301,1302],{"class":66},"))\n",[56,1304,1305,1308,1311,1313,1316,1318,1321,1324],{"class":58,"line":368},[56,1306,1307],{"class":110},"    for",[56,1309,1310],{"class":122}," _",[56,1312,142],{"class":66},[56,1314,1315],{"class":122}," o ",[56,1317,173],{"class":62},[56,1319,1320],{"class":110}," range",[56,1322,1323],{"class":122}," orders ",[56,1325,786],{"class":66},[56,1327,1328,1331,1333,1335,1337,1340,1342,1345,1347,1350],{"class":58,"line":381},[56,1329,1330],{"class":122},"        out ",[56,1332,1078],{"class":62},[56,1334,129],{"class":84},[56,1336,88],{"class":66},[56,1338,1339],{"class":122},"out",[56,1341,142],{"class":66},[56,1343,1344],{"class":122}," o",[56,1346,137],{"class":66},[56,1348,1349],{"class":122},"ID",[56,1351,189],{"class":66},[56,1353,1354],{"class":58,"line":391},[56,1355,1356],{"class":66},"    }\n",[56,1358,1359,1361],{"class":58,"line":396},[56,1360,111],{"class":110},[56,1362,1363],{"class":122}," out\n",[56,1365,1366],{"class":58,"line":401},[56,1367,154],{"class":66},[33,1369,1370,1371,1374,1375,1378,1379,1382,1383,1385],{},"O ",[53,1372,1373],{},"make([]int64, len(orders))"," cria um slice com ",[53,1376,1377],{},"len(orders)"," elementos ",[249,1380,1381],{},"já preenchidos com o zero value",". Cada ",[53,1384,223],{}," acrescenta depois deles:",[46,1387,1390],{"className":1388,"code":1389,"language":215,"meta":51},[213],"[0 0 0 10 20 30] len=6 cap=6\n",[53,1391,1389],{"__ignoreMap":51},[33,1393,1394,1395,1398],{},"A intenção era reservar espaço; o que aconteceu foi criar os elementos. A forma correta é ",[53,1396,1397],{},"make([]int64, 0, len(orders))",": comprimento zero, capacidade reservada.",[33,1400,1401,1402,1404],{},"O detalhe é que esse bug não é só de correção, ele é mais lento do que não ter otimizado nada. Coletando 1000 ",[53,1403,1267],{}," (32 bytes cada):",[46,1406,1409],{"className":1407,"code":1408,"language":215,"meta":51},[213],"BenchmarkNoPrealloc-8       114913     8935 ns\u002Fop     70208 B\u002Fop    10 allocs\u002Fop\nBenchmarkPrealloc-8         290004     3953 ns\u002Fop     32768 B\u002Fop     1 allocs\u002Fop\nBenchmarkWrongPrealloc-8     77742    15990 ns\u002Fop    155648 B\u002Fop     3 allocs\u002Fop\n",[53,1410,1408],{"__ignoreMap":51},[33,1412,1413],{},"A versão sem pré-alocação faz 10 alocações, porque o slice precisou crescer 10 vezes ao longo do caminho. A versão correta faz uma só, e é 2,3× mais rápida.",[33,1415,1416,1417,1420],{},"A versão com o ",[53,1418,1419],{},"make"," errado é a mais interessante das três. Ela termina com um slice de 2000 elementos — os 1000 zeros na frente e os 1000 valores reais depois — e, para chegar lá, alocou três vezes: os 1000 elementos iniciais, e mais duas realocações de crescimento (capacidade 1000 → 1536 → 2304). São os 155.648 B\u002Fop que o benchmark reporta, para produzir um resultado que, além de tudo, está errado. A tentativa de otimizar saiu quase 2× mais cara do que não ter feito nada.",[845,1422,1423],{},[33,1424,1425,1428,1429,1432,1433,1436,1437,137],{},[53,1426,1427],{},"go vet"," não pega esse caso. O linter ",[53,1430,1431],{},"makezero",", disponível no ",[53,1434,1435],{},"golangci-lint",", existe justamente para isso: ele acusa slices criados com comprimento diferente de zero que depois recebem ",[53,1438,223],{},[1440,1441,1443],"h3",{"id":1442},"a-capacidade-também-é-um-pedaço-de-array-que-ainda-está-lá","A capacidade também é um pedaço de array que ainda está lá",[33,1445,1446,1447,304,1449,1451],{},"Uma consequência menos óbvia: os elementos entre ",[53,1448,915],{},[53,1450,918],{}," não desapareceram, eles só não são acessíveis pelo slice atual. Refatiar até a capacidade os traz de volta:",[46,1453,1455],{"className":48,"code":1454,"language":50,"meta":51,"style":51},"s := []int{1, 2, 3, 4, 5}\nt := s[:2]\n\nfmt.Println(t)          \u002F\u002F [1 2]\nfmt.Println(t[:cap(t)]) \u002F\u002F [1 2 3 4 5]\n",[53,1456,1457,1491,1509,1513,1531],{"__ignoreMap":51},[56,1458,1459,1462,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1484,1486,1489],{"class":58,"line":59},[56,1460,1461],{"class":122},"s ",[56,1463,173],{"class":62},[56,1465,629],{"class":66},[56,1467,283],{"class":433},[56,1469,119],{"class":66},[56,1471,691],{"class":426},[56,1473,142],{"class":66},[56,1475,696],{"class":426},[56,1477,142],{"class":66},[56,1479,701],{"class":426},[56,1481,142],{"class":66},[56,1483,1089],{"class":426},[56,1485,142],{"class":66},[56,1487,1488],{"class":426}," 5",[56,1490,154],{"class":66},[56,1492,1493,1496,1498,1501,1504,1506],{"class":58,"line":107},[56,1494,1495],{"class":122},"t ",[56,1497,173],{"class":62},[56,1499,1500],{"class":122}," s",[56,1502,1503],{"class":66},"[:",[56,1505,774],{"class":426},[56,1507,1508],{"class":66},"]\n",[56,1510,1511],{"class":58,"line":151},[56,1512,357],{"emptyLinePlaceholder":356},[56,1514,1515,1517,1519,1521,1523,1526,1528],{"class":58,"line":368},[56,1516,375],{"class":122},[56,1518,137],{"class":66},[56,1520,463],{"class":84},[56,1522,88],{"class":66},[56,1524,1525],{"class":122},"t",[56,1527,81],{"class":66},[56,1529,1530],{"class":483},"          \u002F\u002F [1 2]\n",[56,1532,1533,1535,1537,1539,1541,1543,1545,1547,1549,1551,1554],{"class":58,"line":381},[56,1534,375],{"class":122},[56,1536,137],{"class":66},[56,1538,463],{"class":84},[56,1540,88],{"class":66},[56,1542,1525],{"class":122},[56,1544,1503],{"class":66},[56,1546,918],{"class":84},[56,1548,88],{"class":66},[56,1550,1525],{"class":122},[56,1552,1553],{"class":66},")])",[56,1555,1556],{"class":483}," \u002F\u002F [1 2 3 4 5]\n",[33,1558,1559,1561,1562,1564,1565,1567,1568,1570,1571,1574],{},[53,1560,1525],{}," tem ",[53,1563,915],{}," 2 e ",[53,1566,918],{}," 5. Encurtar um slice não apaga nada; apenas move o ",[53,1569,915],{},". É por isso que \"cortar\" dados sensíveis com ",[53,1572,1573],{},"s = s[:n]"," não é uma forma de descartá-los.",[1440,1576,1578],{"id":1577},"a-expressão-de-três-índices","A expressão de três índices",[33,1580,1581,1582,1585,1586,126],{},"Para limitar a capacidade existe a ",[249,1583,1584],{},"full slice expression",", ",[53,1587,1588],{},"a[low:high:max]",[276,1590,1591,1597],{},[33,1592,1593,1594,284],{},"\"Adicionalmente, ela controla a capacidade do slice resultante, definindo-a como ",[53,1595,1596],{},"max - low",[33,1598,287,1599],{},[37,1600,293,1603],{"href":1601,"rel":1602},"https:\u002F\u002Fgo.dev\u002Fref\u002Fspec#Full_slice_expressions",[292],[295,1604,1605],{},"Full slice expressions",[46,1607,1609],{"className":48,"code":1608,"language":50,"meta":51,"style":51},"all := []int{1, 2, 3, 4, 5}\n\nhead := all[:2]     \u002F\u002F len=2, cap=5\nsafe := all[:2:2]   \u002F\u002F len=2, cap=2\n",[53,1610,1611,1644,1648,1667],{"__ignoreMap":51},[56,1612,1613,1616,1618,1620,1622,1624,1626,1628,1630,1632,1634,1636,1638,1640,1642],{"class":58,"line":59},[56,1614,1615],{"class":122},"all ",[56,1617,173],{"class":62},[56,1619,629],{"class":66},[56,1621,283],{"class":433},[56,1623,119],{"class":66},[56,1625,691],{"class":426},[56,1627,142],{"class":66},[56,1629,696],{"class":426},[56,1631,142],{"class":66},[56,1633,701],{"class":426},[56,1635,142],{"class":66},[56,1637,1089],{"class":426},[56,1639,142],{"class":66},[56,1641,1488],{"class":426},[56,1643,154],{"class":66},[56,1645,1646],{"class":58,"line":107},[56,1647,357],{"emptyLinePlaceholder":356},[56,1649,1650,1653,1655,1658,1660,1662,1664],{"class":58,"line":151},[56,1651,1652],{"class":122},"head ",[56,1654,173],{"class":62},[56,1656,1657],{"class":122}," all",[56,1659,1503],{"class":66},[56,1661,774],{"class":426},[56,1663,430],{"class":66},[56,1665,1666],{"class":483},"     \u002F\u002F len=2, cap=5\n",[56,1668,1669,1672,1674,1676,1678,1680,1682,1684,1686],{"class":58,"line":368},[56,1670,1671],{"class":122},"safe ",[56,1673,173],{"class":62},[56,1675,1657],{"class":122},[56,1677,1503],{"class":66},[56,1679,774],{"class":426},[56,1681,126],{"class":66},[56,1683,774],{"class":426},[56,1685,430],{"class":66},[56,1687,1688],{"class":483},"   \u002F\u002F len=2, cap=2\n",[33,1690,1691,1692,1694],{},"A diferença entre esses dois é a diferença entre o bug da introdução e o código correto, e é para lá que vamos na Parte 4. Antes, precisamos entender o que o ",[53,1693,223],{}," faz quando a capacidade acaba.",[258,1696,1698],{"id":1697},"parte-3-como-o-slice-cresce","Parte 3: como o slice cresce",[33,1700,1701,1702,1705],{},"A spec descreve o comportamento em uma frase, e note o que ela ",[249,1703,1704],{},"não"," promete:",[276,1707,1708,1720],{},[33,1709,1710,1711,1713,1714,1716,1717,1719],{},"\"Se a capacidade de ",[53,1712,1042],{}," não for grande o suficiente para caber os valores adicionais, ",[53,1715,223],{}," aloca um novo array subjacente, suficientemente grande, que caiba tanto os elementos existentes quanto os adicionais. Caso contrário, ",[53,1718,223],{}," reutiliza o array subjacente.\"",[33,1721,287,1722],{},[37,1723,293,1726],{"href":1724,"rel":1725},"https:\u002F\u002Fgo.dev\u002Fref\u002Fspec#Appending_and_copying_slices",[292],[295,1727,1728],{},"Appending to and copying slices",[33,1730,1731],{},"\"Suficientemente grande\" é tudo o que a linguagem garante. Quanto exatamente é decisão do runtime, e ela mudou ao longo das versões.",[33,1733,1734,1735,1738,1739,126],{},"No Go 1.26, quem decide é ",[53,1736,1737],{},"nextslicecap",", em ",[53,1740,1741],{},"runtime\u002Fslice.go",[46,1743,1745],{"className":48,"code":1744,"language":50,"meta":51,"style":51},"func nextslicecap(newLen, oldCap int) int {\n    newcap := oldCap\n    doublecap := newcap + newcap\n    if newLen > doublecap {\n        return newLen\n    }\n\n    const threshold = 256\n    if oldCap \u003C threshold {\n        return doublecap\n    }\n    for {\n        \u002F\u002F Transition from growing 2x for small slices\n        \u002F\u002F to growing 1.25x for large slices. This formula\n        \u002F\u002F gives a smooth-ish transition between the two.\n        newcap += (newcap + 3*threshold) >> 2\n        \u002F\u002F ...\n    }\n}\n",[53,1746,1747,1773,1783,1799,1815,1823,1827,1831,1845,1860,1867,1871,1877,1882,1887,1893,1924,1930,1935],{"__ignoreMap":51},[56,1748,1749,1751,1754,1756,1759,1761,1764,1767,1769,1771],{"class":58,"line":59},[56,1750,63],{"class":62},[56,1752,1753],{"class":84}," nextslicecap",[56,1755,88],{"class":66},[56,1757,1758],{"class":70},"newLen",[56,1760,142],{"class":66},[56,1762,1763],{"class":70}," oldCap",[56,1765,1766],{"class":433}," int",[56,1768,81],{"class":66},[56,1770,1766],{"class":433},[56,1772,104],{"class":66},[56,1774,1775,1778,1780],{"class":58,"line":107},[56,1776,1777],{"class":122},"    newcap ",[56,1779,173],{"class":62},[56,1781,1782],{"class":122}," oldCap\n",[56,1784,1785,1788,1790,1793,1796],{"class":58,"line":151},[56,1786,1787],{"class":122},"    doublecap ",[56,1789,173],{"class":62},[56,1791,1792],{"class":122}," newcap ",[56,1794,1795],{"class":62},"+",[56,1797,1798],{"class":122}," newcap\n",[56,1800,1801,1804,1807,1810,1813],{"class":58,"line":368},[56,1802,1803],{"class":110},"    if",[56,1805,1806],{"class":122}," newLen ",[56,1808,1809],{"class":62},">",[56,1811,1812],{"class":122}," doublecap ",[56,1814,786],{"class":66},[56,1816,1817,1820],{"class":58,"line":381},[56,1818,1819],{"class":110},"        return",[56,1821,1822],{"class":122}," newLen\n",[56,1824,1825],{"class":58,"line":391},[56,1826,1356],{"class":66},[56,1828,1829],{"class":58,"line":396},[56,1830,357],{"emptyLinePlaceholder":356},[56,1832,1833,1836,1840,1842],{"class":58,"line":401},[56,1834,1835],{"class":62},"    const",[56,1837,1839],{"class":1838},"s_hVV"," threshold",[56,1841,1064],{"class":62},[56,1843,1844],{"class":426}," 256\n",[56,1846,1847,1849,1852,1855,1858],{"class":58,"line":414},[56,1848,1803],{"class":110},[56,1850,1851],{"class":122}," oldCap ",[56,1853,1854],{"class":62},"\u003C",[56,1856,1857],{"class":122}," threshold ",[56,1859,786],{"class":66},[56,1861,1862,1864],{"class":58,"line":437},[56,1863,1819],{"class":110},[56,1865,1866],{"class":122}," doublecap\n",[56,1868,1869],{"class":58,"line":450},[56,1870,1356],{"class":66},[56,1872,1873,1875],{"class":58,"line":455},[56,1874,1307],{"class":110},[56,1876,104],{"class":66},[56,1878,1879],{"class":58,"line":487},[56,1880,1881],{"class":483},"        \u002F\u002F Transition from growing 2x for small slices\n",[56,1883,1884],{"class":58,"line":514},[56,1885,1886],{"class":483},"        \u002F\u002F to growing 1.25x for large slices. This formula\n",[56,1888,1890],{"class":58,"line":1889},15,[56,1891,1892],{"class":483},"        \u002F\u002F gives a smooth-ish transition between the two.\n",[56,1894,1896,1899,1902,1904,1907,1909,1911,1913,1916,1918,1921],{"class":58,"line":1895},16,[56,1897,1898],{"class":122},"        newcap ",[56,1900,1901],{"class":62},"+=",[56,1903,67],{"class":66},[56,1905,1906],{"class":122},"newcap ",[56,1908,1795],{"class":62},[56,1910,701],{"class":426},[56,1912,74],{"class":62},[56,1914,1915],{"class":122},"threshold",[56,1917,81],{"class":66},[56,1919,1920],{"class":62}," >>",[56,1922,1923],{"class":426}," 2\n",[56,1925,1927],{"class":58,"line":1926},17,[56,1928,1929],{"class":483},"        \u002F\u002F ...\n",[56,1931,1933],{"class":58,"line":1932},18,[56,1934,1356],{"class":66},[56,1936,1938],{"class":58,"line":1937},19,[56,1939,154],{"class":66},[33,1941,1942],{},"São três regras, em ordem:",[1944,1945,1946,1950,1953],"ol",{},[1947,1948,1949],"li",{},"Se o que você pediu já passa do dobro da capacidade atual, o runtime usa exatamente o que foi pedido. Adicionar 100 elementos a um slice de capacidade 4 não vai gerar capacidade 8.",[1947,1951,1952],{},"Abaixo de 256 elementos de capacidade, dobra.",[1947,1954,1955,1956,1959],{},"A partir de 256, aplica ",[53,1957,1958],{},"newcap += (newcap + 768) \u002F 4",", que começa em fator 2 e vai caindo suavemente em direção a 1,25.",[33,1961,1962],{},"O objetivo da terceira regra é evitar o degrau que existia antes: até o Go 1.17, o fator caía de 2 para 1,25 de uma vez em 1024 elementos.",[1440,1964,1966],{"id":1965},"o-que-você-realmente-observa","O que você realmente observa",[33,1968,1969,1970,1972,1973,1976],{},"Só que ",[53,1971,1737],{}," não é a última palavra. O valor que ela devolve vira uma quantidade de bytes, e o alocador do Go arredonda essa quantidade para a ",[249,1974,1975],{},"size class"," mais próxima, porque ele não aloca blocos de tamanho arbitrário. A capacidade final é o quanto cabe no bloco arredondado.",[33,1978,1979,1980,1983,1984,126],{},"Medindo o crescimento de um ",[53,1981,1982],{},"[]int"," a partir de ",[53,1985,949],{},[46,1987,1990],{"className":1988,"code":1989,"language":215,"meta":51},[213],"len=1     cap=1\nlen=2     cap=2\nlen=3     cap=4\nlen=5     cap=8\n...\nlen=257   cap=512\nlen=513   cap=848      \u003C- a fórmula diz 832\nlen=849   cap=1280\nlen=1281  cap=1792\n",[53,1991,1989],{"__ignoreMap":51},[33,1993,1994,1995,1998,1999,2002,2003,2005],{},"Em ",[53,1996,1997],{},"cap=512",", a fórmula dá ",[53,2000,2001],{},"512 + (512 + 768)\u002F4 = 832",". Mas 832 elementos de 8 bytes são 6656 bytes, e a size class imediatamente acima é 6784 — que comporta 848 elementos. O runtime não joga fora os 16 elementos que sobraram no bloco, então ",[53,2004,918],{}," vira 848.",[33,2007,2008,2009,126],{},"Por isso a sequência depende do tipo do elemento, não só da quantidade. Crescendo um elemento por vez a partir de ",[53,2010,949],{},[864,2012,2013,2026],{},[867,2014,2015],{},[870,2016,2017,2020,2023],{},[873,2018,2019],{},"Tipo",[873,2021,2022],{},"Tamanho do elemento",[873,2024,2025],{},"Capacidades observadas",[888,2027,2028,2041,2053],{},[870,2029,2030,2035,2038],{},[893,2031,2032],{},[53,2033,2034],{},"[]byte",[893,2036,2037],{},"1 B",[893,2039,2040],{},"8, 16, 32, 64, 128, 256, 512, 896, 1408, 2048",[870,2042,2043,2047,2050],{},[893,2044,2045],{},[53,2046,1982],{},[893,2048,2049],{},"8 B",[893,2051,2052],{},"1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 848, 1280, 1792",[870,2054,2055,2060,2063],{},[893,2056,2057],{},[53,2058,2059],{},"[]Order",[893,2061,2062],{},"32 B",[893,2064,2065],{},"1, 2, 4, 8, 16, 35, 71, 151, 303, 575, 1023, 1536",[33,2067,2068,2069,2071,2072,2074,2075,2077,2078,2080,2081,2083],{},"Três coisas para reparar nessa tabela. ",[53,2070,2034],{}," começa em 8, e não em 1, porque a menor size class é de 8 bytes — pedir 1 byte e receber 8 é o piso do alocador. ",[53,2073,1982],{}," segue as potências de dois até 512, onde a fórmula assume e o arredondamento começa a aparecer. E ",[53,2076,2059],{}," sai de 16 direto para 35, um número que não é potência de dois nem múltiplo de nada óbvio: são 32 elementos pela fórmula, arredondados para cima pelo tamanho do bloco, e ainda descontados de um cabeçalho de 8 bytes que o alocador acrescenta porque ",[53,2079,1267],{}," contém uma ",[53,2082,779],{}," — elementos com ponteiros precisam desse metadado para o GC saber o que varrer.",[845,2085,2086],{},[33,2087,2088,2089,2097,2098,2100],{},"A moral prática dessa seção não é decorar a tabela, é o contrário: ",[249,2090,2091,2093,2094,2096],{},[53,2092,918],{}," depois de um ",[53,2095,223],{}," é um detalhe de implementação."," Se o seu código depende de um valor específico de capacidade, ele vai quebrar em alguma versão futura do Go. O que você pode confiar é no comportamento: o crescimento é geométrico, então uma sequência de N ",[53,2099,223],{}," custa O(N) no total, e não O(N²).",[1440,2102,2104],{"id":2103},"uma-surpresa-que-vem-do-artigo-anterior","Uma surpresa que vem do artigo anterior",[33,2106,2107,2108,2110],{},"Se você rodar o teste acima em uma função onde o slice ",[249,2109,1704],{}," escapa, os números mudam:",[46,2112,2114],{"className":48,"code":2113,"language":50,"meta":51,"style":51},"\u002F\u002Fgo:noinline\nfunc firstCapLocal() int {\n    var s []int\n    s = append(s, 1)\n    return cap(s) \u002F\u002F 4\n}\n",[53,2115,2116,2120,2133,2144,2162,2178],{"__ignoreMap":51},[56,2117,2118],{"class":58,"line":59},[56,2119,566],{"class":483},[56,2121,2122,2124,2127,2129,2131],{"class":58,"line":107},[56,2123,63],{"class":62},[56,2125,2126],{"class":84}," firstCapLocal",[56,2128,409],{"class":66},[56,2130,1766],{"class":433},[56,2132,104],{"class":66},[56,2134,2135,2137,2140,2142],{"class":58,"line":151},[56,2136,417],{"class":62},[56,2138,2139],{"class":122}," s ",[56,2141,445],{"class":66},[56,2143,434],{"class":433},[56,2145,2146,2148,2150,2152,2154,2156,2158,2160],{"class":58,"line":368},[56,2147,1075],{"class":122},[56,2149,1078],{"class":62},[56,2151,129],{"class":84},[56,2153,88],{"class":66},[56,2155,1042],{"class":122},[56,2157,142],{"class":66},[56,2159,816],{"class":426},[56,2161,189],{"class":66},[56,2163,2164,2166,2169,2171,2173,2175],{"class":58,"line":381},[56,2165,111],{"class":110},[56,2167,2168],{"class":84}," cap",[56,2170,88],{"class":66},[56,2172,1042],{"class":122},[56,2174,81],{"class":66},[56,2176,2177],{"class":483}," \u002F\u002F 4\n",[56,2179,2180],{"class":58,"line":391},[56,2181,154],{"class":66},[33,2183,2184,2185,2187,2188,2190],{},"Quatro, e não um. E com ",[53,2186,2034],{}," o primeiro ",[53,2189,223],{}," devolve capacidade 32, não 8.",[33,2192,2193,2194,2197,2198,2202,2203,2206,2207,2210],{},"Isso não é o ",[53,2195,2196],{},"growslice"," — é o ",[37,2199,2201],{"href":2200},"\u002Fescape-analysis-em-go-stack-ou-heap","escape analysis"," em ação. Desde o Go 1.25, quando o compilador prova que o slice não sobrevive à função, ele reserva um buffer fixo na stack e usa esse buffer como array inicial. O tamanho padrão é de 32 bytes, definido por ",[53,2204,2205],{},"VariableMakeThreshold"," em ",[53,2208,2209],{},"cmd\u002Fcompile\u002Finternal\u002Fbase\u002Fflag.go",", e a capacidade resultante é o número de elementos que cabem nele:",[46,2212,2214],{"className":48,"code":2213,"language":50,"meta":51,"style":51},"K := maxStackSize \u002F et.Size() \u002F\u002F cmd\u002Fcompile\u002Finternal\u002Fssagen\u002Fssa.go\n",[53,2215,2216],{"__ignoreMap":51},[56,2217,2218,2221,2223,2226,2229,2232,2234,2237,2239],{"class":58,"line":59},[56,2219,2220],{"class":122},"K ",[56,2222,173],{"class":62},[56,2224,2225],{"class":122}," maxStackSize ",[56,2227,2228],{"class":62},"\u002F",[56,2230,2231],{"class":122}," et",[56,2233,137],{"class":66},[56,2235,2236],{"class":84},"Size",[56,2238,409],{"class":66},[56,2240,2241],{"class":483}," \u002F\u002F cmd\u002Fcompile\u002Finternal\u002Fssagen\u002Fssa.go\n",[33,2243,2244,2245,2247,2248,2250,2251,2253],{},"32 \u002F 8 = 4 para ",[53,2246,1982],{},", 32 \u002F 1 = 32 para ",[53,2249,2034],{},", 32 \u002F 32 = 1 para ",[53,2252,2059],{},". Confere com o observado. Basta fazer o slice escapar — atribuindo a uma variável global, por exemplo — para as capacidades voltarem a 1, 8 e 1.",[33,2255,2256,2257,2259],{},"É o mesmo padrão que apareceu no artigo sobre escape analysis: a mesma linha de código produz resultados diferentes conforme o contexto da chamada. Aqui isso é ainda mais uma razão para não tratar ",[53,2258,918],{}," como um número previsível.",[258,2261,2263],{"id":2262},"parte-4-aliasing-ou-quando-dois-slices-enxergam-o-mesmo-array","Parte 4: aliasing, ou quando dois slices enxergam o mesmo array",[33,2265,2266],{},"Agora dá para voltar ao bug da introdução com as ferramentas certas.",[46,2268,2269],{"className":48,"code":49,"language":50,"meta":51,"style":51},[53,2270,2271,2301,2331],{"__ignoreMap":51},[56,2272,2273,2275,2277,2279,2281,2283,2285,2287,2289,2291,2293,2295,2297,2299],{"class":58,"line":59},[56,2274,63],{"class":62},[56,2276,67],{"class":66},[56,2278,71],{"class":70},[56,2280,74],{"class":62},[56,2282,78],{"class":77},[56,2284,81],{"class":66},[56,2286,85],{"class":84},[56,2288,88],{"class":66},[56,2290,91],{"class":70},[56,2292,94],{"class":77},[56,2294,81],{"class":66},[56,2296,99],{"class":62},[56,2298,78],{"class":77},[56,2300,104],{"class":66},[56,2302,2303,2305,2307,2309,2311,2313,2315,2317,2319,2321,2323,2325,2327,2329],{"class":58,"line":107},[56,2304,111],{"class":110},[56,2306,114],{"class":62},[56,2308,78],{"class":77},[56,2310,119],{"class":66},[56,2312,123],{"class":122},[56,2314,126],{"class":66},[56,2316,129],{"class":84},[56,2318,88],{"class":66},[56,2320,134],{"class":122},[56,2322,137],{"class":66},[56,2324,123],{"class":122},[56,2326,142],{"class":66},[56,2328,145],{"class":122},[56,2330,148],{"class":66},[56,2332,2333],{"class":58,"line":151},[56,2334,154],{"class":66},[33,2336,2337,1561,2340,304,2342,2344,2345,2347,2348,2350,2351,2353,2354,2357],{},[53,2338,2339],{},"r.middlewares",[53,2341,234],{},[53,2343,230],{},". O ",[53,2346,223],{}," encontra espaço sobrando, então ",[249,2349,1704],{}," aloca nada: ele escreve ",[53,2352,91],{}," na posição 3 do array existente e devolve um cabeçalho com ",[53,2355,2356],{},"len=4"," apontando para o mesmo array.",[33,2359,2360,2361,2363,2364,2366,2367,2369,2370,2372],{},"Quando ",[53,2362,181],{}," é chamado uma segunda vez a partir do mesmo pai, o cabeçalho de ",[53,2365,2339],{}," continua com ",[53,2368,234],{}," — ele nunca mudou. O ",[53,2371,223],{}," escreve de novo na posição 3, por cima do middleware anterior. Os dois routers filhos terminam com cabeçalhos diferentes, mas apontando para o mesmo array, e o array só tem uma posição 3.",[33,2374,2375,2376,2378],{},"A correção é dizer ao ",[53,2377,223],{}," que ele não tem permissão para usar a capacidade sobrando:",[46,2380,2382],{"className":48,"code":2381,"language":50,"meta":51,"style":51},"func (r *Router) Group(m Middleware) *Router {\n    base := r.middlewares[:len(r.middlewares):len(r.middlewares)]\n    return &Router{middlewares: append(base, m)}\n}\n",[53,2383,2384,2414,2456,2483],{"__ignoreMap":51},[56,2385,2386,2388,2390,2392,2394,2396,2398,2400,2402,2404,2406,2408,2410,2412],{"class":58,"line":59},[56,2387,63],{"class":62},[56,2389,67],{"class":66},[56,2391,71],{"class":70},[56,2393,74],{"class":62},[56,2395,78],{"class":77},[56,2397,81],{"class":66},[56,2399,85],{"class":84},[56,2401,88],{"class":66},[56,2403,91],{"class":70},[56,2405,94],{"class":77},[56,2407,81],{"class":66},[56,2409,99],{"class":62},[56,2411,78],{"class":77},[56,2413,104],{"class":66},[56,2415,2416,2419,2421,2424,2426,2428,2430,2432,2434,2436,2438,2440,2443,2445,2447,2449,2451,2453],{"class":58,"line":107},[56,2417,2418],{"class":122},"    base ",[56,2420,173],{"class":62},[56,2422,2423],{"class":122}," r",[56,2425,137],{"class":66},[56,2427,123],{"class":122},[56,2429,1503],{"class":66},[56,2431,915],{"class":84},[56,2433,88],{"class":66},[56,2435,134],{"class":122},[56,2437,137],{"class":66},[56,2439,123],{"class":122},[56,2441,2442],{"class":66},"):",[56,2444,915],{"class":84},[56,2446,88],{"class":66},[56,2448,134],{"class":122},[56,2450,137],{"class":66},[56,2452,123],{"class":122},[56,2454,2455],{"class":66},")]\n",[56,2457,2458,2460,2462,2464,2466,2468,2470,2472,2474,2477,2479,2481],{"class":58,"line":151},[56,2459,111],{"class":110},[56,2461,114],{"class":62},[56,2463,78],{"class":77},[56,2465,119],{"class":66},[56,2467,123],{"class":122},[56,2469,126],{"class":66},[56,2471,129],{"class":84},[56,2473,88],{"class":66},[56,2475,2476],{"class":122},"base",[56,2478,142],{"class":66},[56,2480,145],{"class":122},[56,2482,148],{"class":66},[56,2484,2485],{"class":58,"line":368},[56,2486,154],{"class":66},[33,2488,2489,2490,2493,2494,2496],{},"Com ",[53,2491,2492],{},"cap == len",", o ",[53,2495,223],{}," é obrigado a alocar um array novo e copiar, e cada filho passa a ter o seu. A biblioteca padrão tem um nome para essa operação desde o Go 1.21:",[46,2498,2500],{"className":48,"code":2499,"language":50,"meta":51,"style":51},"\u002F\u002F Clip removes unused capacity from the slice, returning s[:len(s):len(s)].\nfunc Clip[S ~[]E, E any](s S) S\n",[53,2501,2502,2507],{"__ignoreMap":51},[56,2503,2504],{"class":58,"line":59},[56,2505,2506],{"class":483},"\u002F\u002F Clip removes unused capacity from the slice, returning s[:len(s):len(s)].\n",[56,2508,2509,2511,2514,2516,2519,2522,2524,2527,2529,2532,2535,2538,2540,2543,2545],{"class":58,"line":107},[56,2510,63],{"class":62},[56,2512,2513],{"class":84}," Clip",[56,2515,423],{"class":66},[56,2517,2518],{"class":70},"S",[56,2520,2521],{"class":62}," ~",[56,2523,445],{"class":66},[56,2525,2526],{"class":77},"E",[56,2528,142],{"class":66},[56,2530,2531],{"class":70}," E",[56,2533,2534],{"class":77}," any",[56,2536,2537],{"class":66},"](",[56,2539,1042],{"class":70},[56,2541,2542],{"class":77}," S",[56,2544,81],{"class":66},[56,2546,2547],{"class":77}," S\n",[33,2549,2550],{},"Então a versão que eu escreveria de verdade é:",[46,2552,2554],{"className":48,"code":2553,"language":50,"meta":51,"style":51},"func (r *Router) Group(m Middleware) *Router {\n    return &Router{middlewares: append(slices.Clip(r.middlewares), m)}\n}\n",[53,2555,2556,2586,2627],{"__ignoreMap":51},[56,2557,2558,2560,2562,2564,2566,2568,2570,2572,2574,2576,2578,2580,2582,2584],{"class":58,"line":59},[56,2559,63],{"class":62},[56,2561,67],{"class":66},[56,2563,71],{"class":70},[56,2565,74],{"class":62},[56,2567,78],{"class":77},[56,2569,81],{"class":66},[56,2571,85],{"class":84},[56,2573,88],{"class":66},[56,2575,91],{"class":70},[56,2577,94],{"class":77},[56,2579,81],{"class":66},[56,2581,99],{"class":62},[56,2583,78],{"class":77},[56,2585,104],{"class":66},[56,2587,2588,2590,2592,2594,2596,2598,2600,2602,2604,2607,2609,2612,2614,2616,2618,2620,2623,2625],{"class":58,"line":107},[56,2589,111],{"class":110},[56,2591,114],{"class":62},[56,2593,78],{"class":77},[56,2595,119],{"class":66},[56,2597,123],{"class":122},[56,2599,126],{"class":66},[56,2601,129],{"class":84},[56,2603,88],{"class":66},[56,2605,2606],{"class":122},"slices",[56,2608,137],{"class":66},[56,2610,2611],{"class":84},"Clip",[56,2613,88],{"class":66},[56,2615,134],{"class":122},[56,2617,137],{"class":66},[56,2619,123],{"class":122},[56,2621,2622],{"class":66},"),",[56,2624,145],{"class":122},[56,2626,148],{"class":66},[56,2628,2629],{"class":58,"line":151},[56,2630,154],{"class":66},[46,2632,2635],{"className":2633,"code":2634,"language":215,"meta":51},[213],"admin : [logging recover requestID requireAdmin]\npublic: [logging recover requestID rateLimit]\n",[53,2636,2634],{"__ignoreMap":51},[243,2638,2639],{},[33,2640,2641,2642,2645,2646,2649,2650,2652],{},"O custo dessa correção é uma alocação por chamada, e ela é o ponto. ",[53,2643,2644],{},"slices.Clip"," transforma \"às vezes compartilha, às vezes não\" em \"nunca compartilha\". A regra que eu uso: ",[249,2647,2648],{},"se um slice vai ser guardado em uma struct de vida longa e derivado depois, ele precisa ser clipado ou clonado na fronteira."," Pagar uma alocação previsível é melhor do que depender de um ",[53,2651,918],{}," que ninguém está olhando.",[1440,2654,2656],{"id":2655},"o-mesmo-mecanismo-do-lado-de-dentro","O mesmo mecanismo, do lado de dentro",[33,2658,2659,2660,2662],{},"O aliasing não é só sobre ",[53,2661,223],{}," acidental. Ele também aparece em um padrão bastante recomendado — o filtro sem alocação:",[46,2664,2666],{"className":48,"code":2665,"language":50,"meta":51,"style":51},"\u002F\u002F activeOnly reaproveita o array de origem para não alocar.\nfunc activeOnly(orders []Order) []Order {\n    out := orders[:0]\n    for _, o := range orders {\n        if o.Status != \"cancelled\" {\n            out = append(out, o)\n        }\n    }\n    return out\n}\n",[53,2667,2668,2673,2696,2711,2729,2753,2772,2777,2781,2787],{"__ignoreMap":51},[56,2669,2670],{"class":58,"line":59},[56,2671,2672],{"class":483},"\u002F\u002F activeOnly reaproveita o array de origem para não alocar.\n",[56,2674,2675,2677,2680,2682,2684,2686,2688,2690,2692,2694],{"class":58,"line":107},[56,2676,63],{"class":62},[56,2678,2679],{"class":84}," activeOnly",[56,2681,88],{"class":66},[56,2683,1262],{"class":70},[56,2685,629],{"class":66},[56,2687,1267],{"class":77},[56,2689,81],{"class":66},[56,2691,629],{"class":66},[56,2693,1267],{"class":77},[56,2695,104],{"class":66},[56,2697,2698,2700,2702,2705,2707,2709],{"class":58,"line":151},[56,2699,1281],{"class":122},[56,2701,173],{"class":62},[56,2703,2704],{"class":122}," orders",[56,2706,1503],{"class":66},[56,2708,599],{"class":426},[56,2710,1508],{"class":66},[56,2712,2713,2715,2717,2719,2721,2723,2725,2727],{"class":58,"line":368},[56,2714,1307],{"class":110},[56,2716,1310],{"class":122},[56,2718,142],{"class":66},[56,2720,1315],{"class":122},[56,2722,173],{"class":62},[56,2724,1320],{"class":110},[56,2726,1323],{"class":122},[56,2728,786],{"class":66},[56,2730,2731,2734,2736,2738,2741,2744,2746,2749,2751],{"class":58,"line":381},[56,2732,2733],{"class":110},"        if",[56,2735,1344],{"class":122},[56,2737,137],{"class":66},[56,2739,2740],{"class":122},"Status ",[56,2742,2743],{"class":62},"!=",[56,2745,805],{"class":371},[56,2747,2748],{"class":797},"cancelled",[56,2750,794],{"class":371},[56,2752,104],{"class":66},[56,2754,2755,2758,2760,2762,2764,2766,2768,2770],{"class":58,"line":391},[56,2756,2757],{"class":122},"            out ",[56,2759,1078],{"class":62},[56,2761,129],{"class":84},[56,2763,88],{"class":66},[56,2765,1339],{"class":122},[56,2767,142],{"class":66},[56,2769,1344],{"class":122},[56,2771,189],{"class":66},[56,2773,2774],{"class":58,"line":396},[56,2775,2776],{"class":66},"        }\n",[56,2778,2779],{"class":58,"line":401},[56,2780,1356],{"class":66},[56,2782,2783,2785],{"class":58,"line":414},[56,2784,111],{"class":110},[56,2786,1363],{"class":122},[56,2788,2789],{"class":58,"line":437},[56,2790,154],{"class":66},[33,2792,2793,2794,2796],{},"Ele funciona porque ",[53,2795,1339],{}," sempre escreve em uma posição que já foi lida. E ele destrói a entrada:",[46,2798,2801],{"className":2799,"code":2800,"language":215,"meta":51},[213],"active: [paid paid]\nall   : [paid paid paid]  \u003C- o chamador perdeu o pedido 2\n",[53,2802,2800],{"__ignoreMap":51},[33,2804,2805,2806,2809],{},"Não é um bug do padrão, é o preço dele. O problema aparece quando essa função mora em um pacote de utilidades, com um nome como ",[53,2807,2808],{},"FilterActive",", e quem chama não faz ideia. Se a função é pública, ou você documenta que ela consome a entrada, ou você não reaproveita o array:",[46,2811,2813],{"className":48,"code":2812,"language":50,"meta":51,"style":51},"func activeOnly(orders []Order) []Order {\n    return slices.DeleteFunc(slices.Clone(orders), func(o Order) bool {\n        return o.Status == \"cancelled\"\n    })\n}\n",[53,2814,2815,2837,2882,2900,2905],{"__ignoreMap":51},[56,2816,2817,2819,2821,2823,2825,2827,2829,2831,2833,2835],{"class":58,"line":59},[56,2818,63],{"class":62},[56,2820,2679],{"class":84},[56,2822,88],{"class":66},[56,2824,1262],{"class":70},[56,2826,629],{"class":66},[56,2828,1267],{"class":77},[56,2830,81],{"class":66},[56,2832,629],{"class":66},[56,2834,1267],{"class":77},[56,2836,104],{"class":66},[56,2838,2839,2841,2844,2846,2849,2851,2853,2855,2858,2860,2862,2864,2867,2869,2872,2875,2877,2880],{"class":58,"line":107},[56,2840,111],{"class":110},[56,2842,2843],{"class":122}," slices",[56,2845,137],{"class":66},[56,2847,2848],{"class":84},"DeleteFunc",[56,2850,88],{"class":66},[56,2852,2606],{"class":122},[56,2854,137],{"class":66},[56,2856,2857],{"class":84},"Clone",[56,2859,88],{"class":66},[56,2861,1262],{"class":122},[56,2863,2622],{"class":66},[56,2865,2866],{"class":62}," func",[56,2868,88],{"class":66},[56,2870,2871],{"class":70},"o",[56,2873,2874],{"class":77}," Order",[56,2876,81],{"class":66},[56,2878,2879],{"class":433}," bool",[56,2881,104],{"class":66},[56,2883,2884,2886,2888,2890,2892,2894,2896,2898],{"class":58,"line":151},[56,2885,1819],{"class":110},[56,2887,1344],{"class":122},[56,2889,137],{"class":66},[56,2891,2740],{"class":122},[56,2893,747],{"class":62},[56,2895,805],{"class":371},[56,2897,2748],{"class":797},[56,2899,378],{"class":371},[56,2901,2902],{"class":58,"line":368},[56,2903,2904],{"class":66},"    })\n",[56,2906,2907],{"class":58,"line":381},[56,2908,154],{"class":66},[1440,2910,2912],{"id":2911},"segurar-um-pedaço-é-segurar-o-array-inteiro","Segurar um pedaço é segurar o array inteiro",[33,2914,2915],{},"A última forma de aliasing é a que não corrompe nada, só consome memória. Como o slice guarda um ponteiro para o array, o coletor de lixo não pode liberar o array enquanto qualquer slice apontar para ele — mesmo que esse slice descreva 16 bytes de um array de 10 MiB.",[33,2917,2918],{},"O blog oficial já alertava para isso:",[276,2920,2921,2924],{},[33,2922,2923],{},"\"refatiar um slice não faz uma cópia do array subjacente. O array completo será mantido em memória até que ele não seja mais referenciado.\"",[33,2925,287,2926],{},[37,2927,988,2930],{"href":2928,"rel":2929},"https:\u002F\u002Fgo.dev\u002Fblog\u002Fslices-intro",[292],[295,2931,2932],{},"Go Slices: usage and internals",[33,2934,2935],{},"Um caso concreto: uma função que lê um payload e guarda só um identificador dele.",[46,2937,2939],{"className":48,"code":2938,"language":50,"meta":51,"style":51},"func extractID(payload []byte) []byte {\n    return payload[:16] \u002F\u002F mantém o payload inteiro vivo\n}\n\nfunc extractIDSafe(payload []byte) []byte {\n    return slices.Clone(payload[:16]) \u002F\u002F 16 bytes, e só\n}\n",[53,2940,2941,2965,2982,2986,2990,3013,3037],{"__ignoreMap":51},[56,2942,2943,2945,2948,2950,2953,2955,2957,2959,2961,2963],{"class":58,"line":59},[56,2944,63],{"class":62},[56,2946,2947],{"class":84}," extractID",[56,2949,88],{"class":66},[56,2951,2952],{"class":70},"payload",[56,2954,629],{"class":66},[56,2956,632],{"class":433},[56,2958,81],{"class":66},[56,2960,629],{"class":66},[56,2962,632],{"class":433},[56,2964,104],{"class":66},[56,2966,2967,2969,2972,2974,2977,2979],{"class":58,"line":107},[56,2968,111],{"class":110},[56,2970,2971],{"class":122}," payload",[56,2973,1503],{"class":66},[56,2975,2976],{"class":426},"16",[56,2978,430],{"class":66},[56,2980,2981],{"class":483}," \u002F\u002F mantém o payload inteiro vivo\n",[56,2983,2984],{"class":58,"line":151},[56,2985,154],{"class":66},[56,2987,2988],{"class":58,"line":368},[56,2989,357],{"emptyLinePlaceholder":356},[56,2991,2992,2994,2997,2999,3001,3003,3005,3007,3009,3011],{"class":58,"line":381},[56,2993,63],{"class":62},[56,2995,2996],{"class":84}," extractIDSafe",[56,2998,88],{"class":66},[56,3000,2952],{"class":70},[56,3002,629],{"class":66},[56,3004,632],{"class":433},[56,3006,81],{"class":66},[56,3008,629],{"class":66},[56,3010,632],{"class":433},[56,3012,104],{"class":66},[56,3014,3015,3017,3019,3021,3023,3025,3027,3029,3031,3034],{"class":58,"line":391},[56,3016,111],{"class":110},[56,3018,2843],{"class":122},[56,3020,137],{"class":66},[56,3022,2857],{"class":84},[56,3024,88],{"class":66},[56,3026,2952],{"class":122},[56,3028,1503],{"class":66},[56,3030,2976],{"class":426},[56,3032,3033],{"class":66},"])",[56,3035,3036],{"class":483}," \u002F\u002F 16 bytes, e só\n",[56,3038,3039],{"class":58,"line":396},[56,3040,154],{"class":66},[33,3042,3043],{},"Guardando 20 desses identificadores, com payloads de 10 MiB:",[46,3045,3048],{"className":3046,"code":3047,"language":215,"meta":51},[213],"20 fatias de 16 bytes (sub-slice):    heap = 200.2 MiB\n20 fatias de 16 bytes (slices.Clone): heap =   0.2 MiB\n",[53,3049,3047],{"__ignoreMap":51},[33,3051,3052],{},"Não há vazamento no sentido clássico — tudo será liberado quando os 20 slices morrerem. Mas enquanto eles viverem, o processo carrega 200 MiB para guardar 320 bytes de informação útil. É o tipo de coisa que aparece como \"uso de memória alto e estável\" e não como um leak crescente, o que torna o diagnóstico bem mais chato.",[845,3054,3055],{},[33,3056,3057,3058,3060,3061,3064],{},"O mesmo vale para ",[53,3059,779],{},", que também é um ponteiro mais um comprimento. Fatiar uma string enorme e guardar o pedaço mantém a original viva. A saída é ",[53,3062,3063],{},"strings.Clone",", do Go 1.18.",[258,3066,3068],{"id":3067},"limitações-exceções-e-armadilhas","Limitações, exceções e armadilhas",[33,3070,3071,3076,3077,1585,3080,304,3082,3084,3085,3088,3089,3091,3092,3094],{},[249,3072,1370,3073,3075],{},[53,3074,223],{}," compartilha ou copia, e você não controla qual."," Esta é a armadilha-mãe, e vale enunciá-la de forma explícita: depois de ",[53,3078,3079],{},"b := append(a, x)",[53,3081,37],{},[53,3083,578],{}," podem ou não compartilhar o array, dependendo de ",[53,3086,3087],{},"cap(a)",". Não existe um jeito de perguntar \"esse ",[53,3090,223],{}," alocou?\" que seja útil em produção. Trate o resultado do ",[53,3093,223],{}," como um slice novo e o original como inválido, ou clipe antes.",[33,3096,3097,3100,3101,3104,3105,3107,3108,3110],{},[249,3098,3099],{},"Encurtar um slice não libera nada."," ",[53,3102,3103],{},"s = s[:0]"," zera o ",[53,3106,915],{}," e mantém a capacidade — o que é ótimo para reaproveitar buffers e péssimo se os elementos forem ponteiros, porque o array continua referenciando os objetos. Se o elemento contém ponteiros e o slice tem vida longa, zere a cauda ou use as funções do pacote ",[53,3109,2606],{},", que fazem isso desde o Go 1.22:",[46,3112,3115],{"className":3113,"code":3114,"language":215,"meta":51},[213],"remoção manual com append: slot além do len = &{d}   \u003C- ainda referenciado\nslices.Delete:             slot além do len = \u003Cnil>  \u003C- zerado\n",[53,3116,3114],{"__ignoreMap":51},[33,3118,3119,3125,3126,3129,3130,3132],{},[249,3120,3121,3124],{},[53,3122,3123],{},"slices.Clone"," é uma cópia rasa."," A documentação diz que \"os elementos são copiados por atribuição\". Clonar um ",[53,3127,3128],{},"[]*Order"," te dá um array novo de ponteiros para os mesmos ",[53,3131,1267],{},". Se o objetivo era isolamento de verdade, o clone raso não resolve.",[33,3134,3135],{},[249,3136,3137,3139],{},[53,3138,949],{}," e slice vazio não são a mesma coisa, exceto quando são.",[46,3141,3143],{"className":48,"code":3142,"language":50,"meta":51,"style":51},"var nilSlice []int\nemptySlice := []int{}\n\nnilSlice == nil   \u002F\u002F true\nemptySlice == nil \u002F\u002F false\nlen(nilSlice) == len(emptySlice) \u002F\u002F true\nslices.Equal(nilSlice, emptySlice) \u002F\u002F true\n",[53,3144,3145,3157,3171,3175,3189,3200,3225],{"__ignoreMap":51},[56,3146,3147,3150,3153,3155],{"class":58,"line":59},[56,3148,3149],{"class":62},"var",[56,3151,3152],{"class":122}," nilSlice ",[56,3154,445],{"class":66},[56,3156,434],{"class":433},[56,3158,3159,3162,3164,3166,3168],{"class":58,"line":107},[56,3160,3161],{"class":122},"emptySlice ",[56,3163,173],{"class":62},[56,3165,629],{"class":66},[56,3167,283],{"class":433},[56,3169,3170],{"class":66},"{}\n",[56,3172,3173],{"class":58,"line":151},[56,3174,357],{"emptyLinePlaceholder":356},[56,3176,3177,3180,3182,3186],{"class":58,"line":368},[56,3178,3179],{"class":122},"nilSlice ",[56,3181,747],{"class":62},[56,3183,3185],{"class":3184},"s39Yj"," nil",[56,3187,3188],{"class":483},"   \u002F\u002F true\n",[56,3190,3191,3193,3195,3197],{"class":58,"line":381},[56,3192,3161],{"class":122},[56,3194,747],{"class":62},[56,3196,3185],{"class":3184},[56,3198,3199],{"class":483}," \u002F\u002F false\n",[56,3201,3202,3204,3206,3209,3211,3214,3216,3218,3221,3223],{"class":58,"line":391},[56,3203,915],{"class":84},[56,3205,88],{"class":66},[56,3207,3208],{"class":122},"nilSlice",[56,3210,81],{"class":66},[56,3212,3213],{"class":62}," ==",[56,3215,1164],{"class":84},[56,3217,88],{"class":66},[56,3219,3220],{"class":122},"emptySlice",[56,3222,81],{"class":66},[56,3224,754],{"class":483},[56,3226,3227,3229,3231,3234,3236,3238,3240,3243,3245],{"class":58,"line":396},[56,3228,2606],{"class":122},[56,3230,137],{"class":66},[56,3232,3233],{"class":84},"Equal",[56,3235,88],{"class":66},[56,3237,3208],{"class":122},[56,3239,142],{"class":66},[56,3241,3242],{"class":122}," emptySlice",[56,3244,81],{"class":66},[56,3246,754],{"class":483},[33,3248,3249,1585,3251,1585,3253,304,3255,3258,3259,3261,3262,3265,3266,3269,3270,304,3272,3274],{},[53,3250,223],{},[53,3252,915],{},[53,3254,918],{},[53,3256,3257],{},"range"," tratam os dois igual, então na maior parte do código a diferença não importa. Ela importa em dois lugares: comparações explícitas contra ",[53,3260,949],{}," e serialização. O ",[53,3263,3264],{},"encoding\u002Fjson"," gera ",[53,3267,3268],{},"null"," para um slice ",[53,3271,949],{},[53,3273,445],{}," para um vazio, e essa diferença já quebrou muito cliente. Se a sua API devolve listas, garanta o slice vazio.",[33,3276,3277,3282],{},[249,3278,3279,3281],{},[53,3280,3257],{}," copia o elemento."," Não é específico de slices, mas é onde mais aparece:",[46,3284,3286],{"className":48,"code":3285,"language":50,"meta":51,"style":51},"for _, o := range orders {\n    o.Status = \"paid\" \u002F\u002F altera a cópia, não o slice\n}\nfor i := range orders {\n    orders[i].Status = \"paid\" \u002F\u002F altera o slice\n}\n",[53,3287,3288,3307,3328,3332,3347,3373],{"__ignoreMap":51},[56,3289,3290,3293,3295,3297,3299,3301,3303,3305],{"class":58,"line":59},[56,3291,3292],{"class":110},"for",[56,3294,1310],{"class":122},[56,3296,142],{"class":66},[56,3298,1315],{"class":122},[56,3300,173],{"class":62},[56,3302,1320],{"class":110},[56,3304,1323],{"class":122},[56,3306,786],{"class":66},[56,3308,3309,3312,3314,3316,3318,3320,3323,3325],{"class":58,"line":107},[56,3310,3311],{"class":122},"    o",[56,3313,137],{"class":66},[56,3315,2740],{"class":122},[56,3317,1078],{"class":62},[56,3319,805],{"class":371},[56,3321,3322],{"class":797},"paid",[56,3324,794],{"class":371},[56,3326,3327],{"class":483}," \u002F\u002F altera a cópia, não o slice\n",[56,3329,3330],{"class":58,"line":151},[56,3331,154],{"class":66},[56,3333,3334,3336,3339,3341,3343,3345],{"class":58,"line":368},[56,3335,3292],{"class":110},[56,3337,3338],{"class":122}," i ",[56,3340,173],{"class":62},[56,3342,1320],{"class":110},[56,3344,1323],{"class":122},[56,3346,786],{"class":66},[56,3348,3349,3352,3354,3357,3360,3362,3364,3366,3368,3370],{"class":58,"line":381},[56,3350,3351],{"class":122},"    orders",[56,3353,423],{"class":66},[56,3355,3356],{"class":122},"i",[56,3358,3359],{"class":66},"].",[56,3361,2740],{"class":122},[56,3363,1078],{"class":62},[56,3365,805],{"class":371},[56,3367,3322],{"class":797},[56,3369,794],{"class":371},[56,3371,3372],{"class":483}," \u002F\u002F altera o slice\n",[56,3374,3375],{"class":58,"line":391},[56,3376,154],{"class":66},[33,3378,3379,3380,3383],{},"Para elementos grandes isso também tem custo de cópia, e é um dos poucos casos em que ",[53,3381,3382],{},"for i := range"," é preferível por performance, não só por semântica.",[33,3385,3386,3100,3389,3392,3393,3396,3397,3399],{},[249,3387,3388],{},"Reservar capacidade demais é um custo, não um seguro.",[53,3390,3391],{},"make([]T, 0, 1_000_000)"," aloca o array inteiro na hora, mesmo que você use dez posições. ",[53,3394,3395],{},"slices.Grow"," sofre do mesmo, e é por isso que ele é a ferramenta certa só quando você tem uma estimativa razoável. Quando não tem, deixe o ",[53,3398,223],{}," crescer: o algoritmo geométrico já é uma boa aposta.",[33,3401,3402,3405,3406,3409,3410,3413,3414,3417],{},[249,3403,3404],{},"Não otimize capacidade sem medir."," Vale aqui o mesmo critério do artigo sobre escape analysis. ",[53,3407,3408],{},"allocs\u002Fop"," só importa em caminhos quentes, e a diferença entre 10 alocações e 1 em uma função chamada três vezes por requisição não paga a complexidade de calcular o tamanho certo. Comece pelo ",[53,3411,3412],{},"-benchmem"," e pelo ",[53,3415,3416],{},"pprof",", não pelo código.",[258,3419,3421],{"id":3420},"mudanças-entre-versões","Mudanças entre versões",[33,3423,3424],{},"Boa parte do que está aqui é comportamento observável, não contrato, e mudou ao longo do tempo:",[864,3426,3427,3437],{},[867,3428,3429],{},[870,3430,3431,3434],{},[873,3432,3433],{},"Versão",[873,3435,3436],{},"O que mudou",[888,3438,3439,3450,3479,3503,3523],{},[870,3440,3441,3444],{},[893,3442,3443],{},"Go 1.18",[893,3445,3446,3447,137],{},"A fórmula de crescimento passou a ser suave: em vez de dobrar até 1024 e depois multiplicar por 1,25, o fator começa a cair em 256. As release notes dizem apenas que \"a nova fórmula é menos propensa a transições bruscas no comportamento de alocação\"; os detalhes estão no commit ",[53,3448,3449],{},"2dda92f",[870,3451,3452,3455],{},[893,3453,3454],{},"Go 1.21",[893,3456,3457,3458,3460,3461,1585,3463,1585,3465,1585,3468,1585,3471,1585,3473,3476,3477,137],{},"O pacote ",[53,3459,2606],{}," entrou na biblioteca padrão, com ",[53,3462,2857],{},[53,3464,2611],{},[53,3466,3467],{},"Grow",[53,3469,3470],{},"Delete",[53,3472,3233],{},[53,3474,3475],{},"Insert"," e companhia. Antes disso, cada projeto tinha a sua versão de ",[53,3478,2611],{},[870,3480,3481,3484],{},[893,3482,3483],{},"Go 1.22",[893,3485,3486,1585,3488,1585,3490,1585,3493,304,3496,3499,3500,137],{},[53,3487,3470],{},[53,3489,2848],{},[53,3491,3492],{},"Compact",[53,3494,3495],{},"CompactFunc",[53,3497,3498],{},"Replace"," passaram a zerar os elementos entre o novo e o antigo comprimento, resolvendo a retenção de ponteiros na cauda. Também chegou ",[53,3501,3502],{},"slices.Concat",[870,3504,3505,3508],{},[893,3506,3507],{},"Go 1.25",[893,3509,3510,3511,3513,3514,3516,3517,3519,3520,137],{},"O compilador passou a alocar o array subjacente de slices na stack em mais situações (\"Faster slices\" nas release notes). É o que faz o primeiro ",[53,3512,223],{}," em um ",[53,3515,1982],{}," local devolver ",[53,3518,230],{},". Pode ser desligado com ",[53,3521,3522],{},"-gcflags=all=-d=variablemakehash=n",[870,3524,3525,3527],{},[893,3526,251],{},[893,3528,3529,3530,137],{},"A mesma otimização foi estendida a mais casos. Nada mudou na semântica; mudou o que você observa em ",[53,3531,918],{},[33,3533,3534,3535,3537,3538,3541,3542,3544,3545,3548],{},"Se você mantém código que nasceu antes do Go 1.21, vale uma busca por implementações caseiras de ",[53,3536,2611],{}," e por remoções feitas com ",[53,3539,3540],{},"append(s[:i], s[i+1:]...)",". As primeiras podem ser trocadas por ",[53,3543,2644],{},"; as segundas provavelmente estão segurando ponteiros na cauda, e ",[53,3546,3547],{},"slices.Delete"," resolve.",[258,3550,3552],{"id":3551},"juntando-tudo-o-caminho-mental","Juntando tudo: o caminho mental",[33,3554,3555],{},"Se eu tivesse que resumir o raciocínio em uma sequência de perguntas:",[1944,3557,3558,3564,3579,3589,3601],{},[1947,3559,3560,3563],{},[249,3561,3562],{},"Eu preciso mesmo de um array?"," Quase sempre não. Array faz sentido quando o tamanho é fixo por natureza (um hash de 32 bytes, um par método\u002Frota como chave de map) ou quando você quer comparabilidade. Fora isso, slice.",[1947,3565,3566,3569,3570,3572,3573,3575,3576,3578],{},[249,3567,3568],{},"Esse slice vai ser guardado em algum lugar que sobrevive à função?"," Se vai, decida na fronteira: ",[53,3571,3123],{}," se você precisa de dados próprios, ",[53,3574,2644],{}," se você só quer impedir que um ",[53,3577,223],{}," futuro pise em memória alheia.",[1947,3580,3581,3584,3585,3588],{},[249,3582,3583],{},"Eu sei quantos elementos vão entrar?"," Se sei, ",[53,3586,3587],{},"make([]T, 0, n)"," — com o zero no meio. Se não sei, deixe crescer.",[1947,3590,3591,3594,3595,3597,3598,3600],{},[249,3592,3593],{},"Essa função muta o slice que recebeu?"," Se muta, isso faz parte do contrato dela e precisa estar documentado. \"Recebe ",[53,3596,886],{}," e devolve ",[53,3599,886],{},"\" não diz se a entrada continua válida.",[1947,3602,3603,3606],{},[249,3604,3605],{},"Estou guardando um pedaço de algo grande?"," Se estou, clone. O array subjacente inteiro fica vivo enquanto qualquer fatia dele existir.",[33,3608,3609,3610,304,3612,3614,3615,3617],{},"O que eu levaria deste artigo é que quase todo problema com slices vem de tratar o cabeçalho como se fosse o dado. Ele não é: ele é uma vista sobre um dado que mora em outro lugar e pode ser visto por mais gente. ",[53,3611,915],{},[53,3613,918],{}," diferentes não são um detalhe de eficiência, são a informação de que existe memória ali que o seu slice não está mostrando — e que o próximo ",[53,3616,223],{}," pode usar.",[33,3619,3620,3621,3624,3625,3627],{},"Nos ",[37,3622,3623],{"href":39},"zero values"," o ganho era não precisar lembrar de inicializar. No ",[37,3626,2201],{"href":2200}," era não precisar decidir onde as coisas moram. Com slices o acordo é diferente: Go te dá uma abstração barata sobre memória compartilhada e, em troca, espera que você saiba que ela é compartilhada. É a única das três em que a linguagem não decide por você.",[258,3629,3631],{"id":3630},"referências","Referências",[3633,3634,3635,3642,3649,3659,3669,3677,3687,3694,3712,3722,3734,3745,3755,3766,3784,3795,3803,3821],"ul",{},[1947,3636,3637,3641],{},[37,3638,3640],{"href":328,"rel":3639},[292],"The Go Programming Language Specification — Slice types"," — a definição de slice como descritor e a frase sobre compartilhamento de armazenamento.",[1947,3643,3644,3648],{},[37,3645,3647],{"href":290,"rel":3646},[292],"The Go Programming Language Specification — Array types"," — o tamanho como parte do tipo.",[1947,3650,3651,3655,3656,3658],{},[37,3652,3654],{"href":1601,"rel":3653},[292],"The Go Programming Language Specification — Full slice expressions"," — a sintaxe ",[53,3657,1588],{}," e como ela define a capacidade.",[1947,3660,3661,3665,3666,3668],{},[37,3662,3664],{"href":1724,"rel":3663},[292],"The Go Programming Language Specification — Appending to and copying slices"," — o que ",[53,3667,223],{}," garante, e o que ele não garante.",[1947,3670,3671,3676],{},[37,3672,3675],{"href":3673,"rel":3674},"https:\u002F\u002Fgo.dev\u002Fref\u002Fspec#Comparison_operators",[292],"The Go Programming Language Specification — Comparison operators"," — por que arrays são comparáveis e slices não.",[1947,3678,3679,3683,3684,3686],{},[37,3680,3682],{"href":986,"rel":3681},[292],"Go Blog — Arrays, slices (and strings): The mechanics of 'append'"," — a explicação canônica do cabeçalho de três palavras e de por que ",[53,3685,223],{}," devolve um valor.",[1947,3688,3689,3693],{},[37,3690,3692],{"href":2928,"rel":3691},[292],"Go Blog — Go Slices: usage and internals"," — o alerta sobre refatiar manter o array inteiro vivo.",[1947,3695,3696,3702,3703,304,3705,3707,3708,3711],{},[37,3697,3700],{"href":3698,"rel":3699},"https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fblob\u002Fmaster\u002Fsrc\u002Fruntime\u002Fslice.go",[292],[53,3701,1741],{}," — ",[53,3704,2196],{},[53,3706,1737],{},", com o ",[53,3709,3710],{},"threshold = 256"," e a fórmula de transição.",[1947,3713,3714,3721],{},[37,3715,3718],{"href":3716,"rel":3717},"https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fblob\u002Fmaster\u002Fsrc\u002Finternal\u002Fruntime\u002Fgc\u002Fsizeclasses.go",[292],[53,3719,3720],{},"internal\u002Fruntime\u002Fgc\u002Fsizeclasses.go"," — a tabela de size classes que explica por que a capacidade observada não bate com a fórmula.",[1947,3723,3724,3702,3730,3733],{},[37,3725,3728],{"href":3726,"rel":3727},"https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fblob\u002Fmaster\u002Fsrc\u002Fcmd\u002Fcompile\u002Finternal\u002Fbase\u002Fflag.go",[292],[53,3729,2209],{},[53,3731,3732],{},"VariableMakeThreshold = 32",", o tamanho do buffer na stack para slices que não escapam.",[1947,3735,3736,3744],{},[37,3737,3740,3741,3743],{"href":3738,"rel":3739},"https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fcommit\u002F2dda92ff6f9f07eeb110ecbf0fc2d7a0ddd27f9d",[292],"commit ",[53,3742,3449],{}," — runtime: make slice growth formula a bit smoother"," — a mudança da fórmula de crescimento e a justificativa do limite de 256.",[1947,3746,3747,3752,3753,137],{},[37,3748,3751],{"href":3749,"rel":3750},"https:\u002F\u002Fgo.dev\u002Fdoc\u002Fgo1.18",[292],"Go 1.18 Release Notes"," — a menção oficial à nova fórmula do ",[53,3754,223],{},[1947,3756,3757,3762,3763,3765],{},[37,3758,3761],{"href":3759,"rel":3760},"https:\u002F\u002Fgo.dev\u002Fdoc\u002Fgo1.21",[292],"Go 1.21 Release Notes"," — a entrada do pacote ",[53,3764,2606],{}," na biblioteca padrão.",[1947,3767,3768,3773,3774,1585,3776,304,3778,3780,3781,137],{},[37,3769,3772],{"href":3770,"rel":3771},"https:\u002F\u002Fgo.dev\u002Fdoc\u002Fgo1.22",[292],"Go 1.22 Release Notes"," — o zeramento da cauda em ",[53,3775,3470],{},[53,3777,3492],{},[53,3779,3498],{},", e a chegada de ",[53,3782,3783],{},"Concat",[1947,3785,3786,3791,3792,137],{},[37,3787,3790],{"href":3788,"rel":3789},"https:\u002F\u002Fgo.dev\u002Fdoc\u002Fgo1.25",[292],"Go 1.25 Release Notes — Faster slices"," — a alocação do array subjacente na stack e a flag ",[53,3793,3794],{},"variablemakehash",[1947,3796,3797,3802],{},[37,3798,3801],{"href":3799,"rel":3800},"https:\u002F\u002Fgo.dev\u002Fdoc\u002Fgo1.26",[292],"Go 1.26 Release Notes — Compiler"," — a extensão da mesma otimização.",[1947,3804,3805,3702,3812,1585,3814,1585,3816,1585,3818,3820],{},[37,3806,3809,3810],{"href":3807,"rel":3808},"https:\u002F\u002Fpkg.go.dev\u002Fslices",[292],"Documentação do pacote ",[53,3811,2606],{},[53,3813,2857],{},[53,3815,2611],{},[53,3817,3467],{},[53,3819,3470],{}," e o contrato de cada uma, incluindo a cópia rasa.",[1947,3822,3823,3829,3830,3833,3834,137],{},[37,3824,3827],{"href":3825,"rel":3826},"https:\u002F\u002Fgithub.com\u002Fashanbrown\u002Fmakezero",[292],[53,3828,1431],{}," — o linter que pega ",[53,3831,3832],{},"make([]T, n)"," seguido de ",[53,3835,223],{},[3837,3838,3839],"style",{},"html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--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 .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 .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":51,"searchDepth":107,"depth":107,"links":3841},[3842,3843,3844,3849,3853,3857,3858,3859,3860],{"id":260,"depth":107,"text":261},{"id":964,"depth":107,"text":965},{"id":1228,"depth":107,"text":3845,"children":3846},"Parte 2: len não é cap",[3847,3848],{"id":1442,"depth":151,"text":1443},{"id":1577,"depth":151,"text":1578},{"id":1697,"depth":107,"text":1698,"children":3850},[3851,3852],{"id":1965,"depth":151,"text":1966},{"id":2103,"depth":151,"text":2104},{"id":2262,"depth":107,"text":2263,"children":3854},[3855,3856],{"id":2655,"depth":151,"text":2656},{"id":2911,"depth":151,"text":2912},{"id":3067,"depth":107,"text":3068},{"id":3420,"depth":107,"text":3421},{"id":3551,"depth":107,"text":3552},{"id":3630,"depth":107,"text":3631},"2026-07-27","Como slices funcionam por dentro em Go: o cabeçalho de três palavras, a diferença entre len e cap, como o append faz o slice crescer, e por que dois slices podem enxergar o mesmo array sem você perceber.","md","https:\u002F\u002Fencrypted-tbn0.gstatic.com\u002Fimages?q=tbn:ANd9GcQvXqKsNKgbxpINxN06GeyY8UPggpH6RUlMZtcJwYptYOPdaD3k4-nHOzd5&s=10",{},22,{"title":10,"description":3862},"qHAFweD2FOxqucnfpAZQJLsolSB42YJ2kbloaVRJqvA",1786023409655]