[{"data":1,"prerenderedAt":4056},["ShallowReactive",2],{"content:\u002F01-basics\u002F03-map":3},{"title":4,"description":5,"path":6,"body":7},"Map в Go","Map — одна из самых часто используемых структур данных в Go, и одна из самых опасных с точки зрения скрытых граблей. Чтобы уверенно отвечать на вопросы о ней, нужно понимать не только API, но и то, что происходит внутри — причём это \"внутри\" кардинально изменилось в Go 1.24.","\u002F01-basics\u002F03-map",{"type":8,"value":9,"toc":4033},"minimark",[10,13,16,21,211,216,421,425,518,526,528,532,543,663,666,734,736,740,743,822,829,834,1333,1339,1341,1345,1348,1354,1382,1390,1395,1402,1404,1408,1415,1419,1429,1435,1438,1453,1456,1469,1473,1476,1491,1498,1504,1507,1514,1518,1525,1536,1540,1638,1640,1644,1648,1654,1775,1778,1782,1834,1838,1950,1953,1955,1959,1969,2090,2096,2155,2164,2166,2170,2179,2190,2201,2212,2223,2231,2239,2247,2269,2292,2306,2308,2312,2413,2471,2659,2855,2857,2861,2863,2868,2874,2880,2890,2895,2901,2906,3124,3126,3131,3136,3141,3149,3153,3159,3163,3425,3427,3432,3437,3442,3454,3458,3464,3470,3474,4029],[11,12,5],"p",{},[14,15],"hr",{},[17,18,20],"h2",{"id":19},"базовый-синтаксис","Базовый синтаксис",[22,23,28],"pre",{"className":24,"code":25,"language":26,"meta":27,"style":27},"language-go shiki shiki-themes github-dark","\u002F\u002F Объявление — nil map, читать можно, писать нельзя\nvar m map[string]int\n\n\u002F\u002F Создание через литерал\nm := map[string]int{\n    \"alice\": 42,\n    \"bob\":   17,\n}\n\n\u002F\u002F Создание через make — предпочтительно, если размер примерно известен\nm := make(map[string]int)\nm := make(map[string]int, 100) \u002F\u002F hint — начальная ёмкость, не жёсткое ограничение\n","go","",[29,30,31,40,66,73,79,103,120,134,140,145,151,178],"code",{"__ignoreMap":27},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sAwPA","\u002F\u002F Объявление — nil map, читать можно, писать нельзя\n",[32,41,43,47,51,54,57,60,63],{"class":34,"line":42},2,[32,44,46],{"class":45},"snl16","var",[32,48,50],{"class":49},"s95oV"," m ",[32,52,53],{"class":45},"map",[32,55,56],{"class":49},"[",[32,58,59],{"class":45},"string",[32,61,62],{"class":49},"]",[32,64,65],{"class":45},"int\n",[32,67,69],{"class":34,"line":68},3,[32,70,72],{"emptyLinePlaceholder":71},true,"\n",[32,74,76],{"class":34,"line":75},4,[32,77,78],{"class":38},"\u002F\u002F Создание через литерал\n",[32,80,82,85,88,91,93,95,97,100],{"class":34,"line":81},5,[32,83,84],{"class":49},"m ",[32,86,87],{"class":45},":=",[32,89,90],{"class":45}," map",[32,92,56],{"class":49},[32,94,59],{"class":45},[32,96,62],{"class":49},[32,98,99],{"class":45},"int",[32,101,102],{"class":49},"{\n",[32,104,106,110,113,117],{"class":34,"line":105},6,[32,107,109],{"class":108},"sU2Wk","    \"alice\"",[32,111,112],{"class":49},": ",[32,114,116],{"class":115},"sDLfK","42",[32,118,119],{"class":49},",\n",[32,121,123,126,129,132],{"class":34,"line":122},7,[32,124,125],{"class":108},"    \"bob\"",[32,127,128],{"class":49},":   ",[32,130,131],{"class":115},"17",[32,133,119],{"class":49},[32,135,137],{"class":34,"line":136},8,[32,138,139],{"class":49},"}\n",[32,141,143],{"class":34,"line":142},9,[32,144,72],{"emptyLinePlaceholder":71},[32,146,148],{"class":34,"line":147},10,[32,149,150],{"class":38},"\u002F\u002F Создание через make — предпочтительно, если размер примерно известен\n",[32,152,154,156,158,162,165,167,169,171,173,175],{"class":34,"line":153},11,[32,155,84],{"class":49},[32,157,87],{"class":45},[32,159,161],{"class":160},"svObZ"," make",[32,163,164],{"class":49},"(",[32,166,53],{"class":45},[32,168,56],{"class":49},[32,170,59],{"class":45},[32,172,62],{"class":49},[32,174,99],{"class":45},[32,176,177],{"class":49},")\n",[32,179,181,183,185,187,189,191,193,195,197,199,202,205,208],{"class":34,"line":180},12,[32,182,84],{"class":49},[32,184,87],{"class":45},[32,186,161],{"class":160},[32,188,164],{"class":49},[32,190,53],{"class":45},[32,192,56],{"class":49},[32,194,59],{"class":45},[32,196,62],{"class":49},[32,198,99],{"class":45},[32,200,201],{"class":49},", ",[32,203,204],{"class":115},"100",[32,206,207],{"class":49},") ",[32,209,210],{"class":38},"\u002F\u002F hint — начальная ёмкость, не жёсткое ограничение\n",[212,213,215],"h3",{"id":214},"чтение-и-безопасная-проверка-существования","Чтение и безопасная проверка существования",[22,217,219],{"className":24,"code":218,"language":26,"meta":27,"style":27},"m := map[string]int{\"alice\": 42}\n\nv := m[\"alice\"]          \u002F\u002F 42\n_ = v\nv = m[\"unknown\"]         \u002F\u002F 0 — zero value, не паника\n_ = v\n\n\u002F\u002F Двухзначная форма — единственный способ отличить \"нет ключа\" от \"значение = 0\"\nv, ok := m[\"alice\"]\nif ok {\n    fmt.Println(v)\n}\n\n\u002F\u002F Классическая ошибка: проверять на zero value вместо ok\ncount := m[\"visits\"]  \u002F\u002F 0 — но существует ли ключ?\n_ = count\ncount, exists := m[\"visits\"]  \u002F\u002F правильно\n_, _ = count, exists\n",[29,220,221,249,253,271,282,299,307,311,316,330,338,349,353,358,364,383,393,410],{"__ignoreMap":27},[32,222,223,225,227,229,231,233,235,237,240,243,245,247],{"class":34,"line":35},[32,224,84],{"class":49},[32,226,87],{"class":45},[32,228,90],{"class":45},[32,230,56],{"class":49},[32,232,59],{"class":45},[32,234,62],{"class":49},[32,236,99],{"class":45},[32,238,239],{"class":49},"{",[32,241,242],{"class":108},"\"alice\"",[32,244,112],{"class":49},[32,246,116],{"class":115},[32,248,139],{"class":49},[32,250,251],{"class":34,"line":42},[32,252,72],{"emptyLinePlaceholder":71},[32,254,255,258,260,263,265,268],{"class":34,"line":68},[32,256,257],{"class":49},"v ",[32,259,87],{"class":45},[32,261,262],{"class":49}," m[",[32,264,242],{"class":108},[32,266,267],{"class":49},"]          ",[32,269,270],{"class":38},"\u002F\u002F 42\n",[32,272,273,276,279],{"class":34,"line":75},[32,274,275],{"class":49},"_ ",[32,277,278],{"class":45},"=",[32,280,281],{"class":49}," v\n",[32,283,284,286,288,290,293,296],{"class":34,"line":81},[32,285,257],{"class":49},[32,287,278],{"class":45},[32,289,262],{"class":49},[32,291,292],{"class":108},"\"unknown\"",[32,294,295],{"class":49},"]         ",[32,297,298],{"class":38},"\u002F\u002F 0 — zero value, не паника\n",[32,300,301,303,305],{"class":34,"line":105},[32,302,275],{"class":49},[32,304,278],{"class":45},[32,306,281],{"class":49},[32,308,309],{"class":34,"line":122},[32,310,72],{"emptyLinePlaceholder":71},[32,312,313],{"class":34,"line":136},[32,314,315],{"class":38},"\u002F\u002F Двухзначная форма — единственный способ отличить \"нет ключа\" от \"значение = 0\"\n",[32,317,318,321,323,325,327],{"class":34,"line":142},[32,319,320],{"class":49},"v, ok ",[32,322,87],{"class":45},[32,324,262],{"class":49},[32,326,242],{"class":108},[32,328,329],{"class":49},"]\n",[32,331,332,335],{"class":34,"line":147},[32,333,334],{"class":45},"if",[32,336,337],{"class":49}," ok {\n",[32,339,340,343,346],{"class":34,"line":153},[32,341,342],{"class":49},"    fmt.",[32,344,345],{"class":160},"Println",[32,347,348],{"class":49},"(v)\n",[32,350,351],{"class":34,"line":180},[32,352,139],{"class":49},[32,354,356],{"class":34,"line":355},13,[32,357,72],{"emptyLinePlaceholder":71},[32,359,361],{"class":34,"line":360},14,[32,362,363],{"class":38},"\u002F\u002F Классическая ошибка: проверять на zero value вместо ok\n",[32,365,367,370,372,374,377,380],{"class":34,"line":366},15,[32,368,369],{"class":49},"count ",[32,371,87],{"class":45},[32,373,262],{"class":49},[32,375,376],{"class":108},"\"visits\"",[32,378,379],{"class":49},"]  ",[32,381,382],{"class":38},"\u002F\u002F 0 — но существует ли ключ?\n",[32,384,386,388,390],{"class":34,"line":385},16,[32,387,275],{"class":49},[32,389,278],{"class":45},[32,391,392],{"class":49}," count\n",[32,394,396,399,401,403,405,407],{"class":34,"line":395},17,[32,397,398],{"class":49},"count, exists ",[32,400,87],{"class":45},[32,402,262],{"class":49},[32,404,376],{"class":108},[32,406,379],{"class":49},[32,408,409],{"class":38},"\u002F\u002F правильно\n",[32,411,413,416,418],{"class":34,"line":412},18,[32,414,415],{"class":49},"_, _ ",[32,417,278],{"class":45},[32,419,420],{"class":49}," count, exists\n",[212,422,424],{"id":423},"удаление-и-итерация","Удаление и итерация",[22,426,428],{"className":24,"code":427,"language":26,"meta":27,"style":27},"m := map[string]int{\"alice\": 42, \"bob\": 17}\n\ndelete(m, \"alice\")  \u002F\u002F безопасно даже если ключа нет\n\nfor k, v := range m {\n    fmt.Println(k, v)\n}\n",[29,429,430,465,469,485,489,505,514],{"__ignoreMap":27},[32,431,432,434,436,438,440,442,444,446,448,450,452,454,456,459,461,463],{"class":34,"line":35},[32,433,84],{"class":49},[32,435,87],{"class":45},[32,437,90],{"class":45},[32,439,56],{"class":49},[32,441,59],{"class":45},[32,443,62],{"class":49},[32,445,99],{"class":45},[32,447,239],{"class":49},[32,449,242],{"class":108},[32,451,112],{"class":49},[32,453,116],{"class":115},[32,455,201],{"class":49},[32,457,458],{"class":108},"\"bob\"",[32,460,112],{"class":49},[32,462,131],{"class":115},[32,464,139],{"class":49},[32,466,467],{"class":34,"line":42},[32,468,72],{"emptyLinePlaceholder":71},[32,470,471,474,477,479,482],{"class":34,"line":68},[32,472,473],{"class":160},"delete",[32,475,476],{"class":49},"(m, ",[32,478,242],{"class":108},[32,480,481],{"class":49},")  ",[32,483,484],{"class":38},"\u002F\u002F безопасно даже если ключа нет\n",[32,486,487],{"class":34,"line":75},[32,488,72],{"emptyLinePlaceholder":71},[32,490,491,494,497,499,502],{"class":34,"line":81},[32,492,493],{"class":45},"for",[32,495,496],{"class":49}," k, v ",[32,498,87],{"class":45},[32,500,501],{"class":45}," range",[32,503,504],{"class":49}," m {\n",[32,506,507,509,511],{"class":34,"line":105},[32,508,342],{"class":49},[32,510,345],{"class":160},[32,512,513],{"class":49},"(k, v)\n",[32,515,516],{"class":34,"line":122},[32,517,139],{"class":49},[11,519,520,521,525],{},"Порядок итерации ",[522,523,524],"strong",{},"не гарантирован"," и намеренно рандомизирован с Go 1.0. Рандомизация введена специально, чтобы разработчики не полагались на случайно воспроизводимый порядок.",[14,527],{},[17,529,531],{"id":530},"что-может-быть-ключом","Что может быть ключом",[11,533,534,535,538,539,542],{},"Ключом может быть любой ",[522,536,537],{},"comparable"," тип — тот, для которого определён оператор ",[29,540,541],{},"==",":",[22,544,546],{"className":24,"code":545,"language":26,"meta":27,"style":27},"\u002F\u002F Можно использовать как ключ\nmap[string]int\nmap[int]string\nmap[[3]int]string   \u002F\u002F массив — comparable\nmap[struct{ X, Y int }]string  \u002F\u002F struct из comparable полей\n\n\u002F\u002F Нельзя — не comparable\n\u002F\u002F map[[]int]string    \u002F\u002F слайс\n\u002F\u002F map[map[string]int]string \u002F\u002F map\n\u002F\u002F map[func()]string   \u002F\u002F функция\n",[29,547,548,553,565,578,599,630,634,639,647,655],{"__ignoreMap":27},[32,549,550],{"class":34,"line":35},[32,551,552],{"class":38},"\u002F\u002F Можно использовать как ключ\n",[32,554,555,557,559,561,563],{"class":34,"line":42},[32,556,53],{"class":45},[32,558,56],{"class":49},[32,560,59],{"class":45},[32,562,62],{"class":49},[32,564,65],{"class":45},[32,566,567,569,571,573,575],{"class":34,"line":68},[32,568,53],{"class":45},[32,570,56],{"class":49},[32,572,99],{"class":45},[32,574,62],{"class":49},[32,576,577],{"class":45},"string\n",[32,579,580,582,585,588,590,592,594,596],{"class":34,"line":75},[32,581,53],{"class":45},[32,583,584],{"class":49},"[[",[32,586,587],{"class":115},"3",[32,589,62],{"class":49},[32,591,99],{"class":45},[32,593,62],{"class":49},[32,595,59],{"class":45},[32,597,598],{"class":38},"   \u002F\u002F массив — comparable\n",[32,600,601,603,605,608,611,614,616,619,622,625,627],{"class":34,"line":81},[32,602,53],{"class":45},[32,604,56],{"class":49},[32,606,607],{"class":45},"struct",[32,609,610],{"class":49},"{ ",[32,612,613],{"class":160},"X",[32,615,201],{"class":49},[32,617,618],{"class":160},"Y",[32,620,621],{"class":45}," int",[32,623,624],{"class":49}," }]",[32,626,59],{"class":45},[32,628,629],{"class":38},"  \u002F\u002F struct из comparable полей\n",[32,631,632],{"class":34,"line":105},[32,633,72],{"emptyLinePlaceholder":71},[32,635,636],{"class":34,"line":122},[32,637,638],{"class":38},"\u002F\u002F Нельзя — не comparable\n",[32,640,641,644],{"class":34,"line":136},[32,642,643],{"class":38},"\u002F\u002F map[[]int]string",[32,645,646],{"class":38},"    \u002F\u002F слайс\n",[32,648,649,652],{"class":34,"line":142},[32,650,651],{"class":38},"\u002F\u002F map[map[string]int]string",[32,653,654],{"class":38}," \u002F\u002F map\n",[32,656,657,660],{"class":34,"line":147},[32,658,659],{"class":38},"\u002F\u002F map[func()]string",[32,661,662],{"class":38},"   \u002F\u002F функция\n",[11,664,665],{},"Интерфейсы как ключи допустимы синтаксически, но опасны: если в рантайме интерфейс содержит несравниваемый тип — паника:",[22,667,669],{"className":24,"code":668,"language":26,"meta":27,"style":27},"var m = map[interface{}]int{}\nm[1] = 1      \u002F\u002F ок\nm[[]int{1}] = 1 \u002F\u002F panic: runtime error: hash of unhashable type []int\n",[29,670,671,694,713],{"__ignoreMap":27},[32,672,673,675,677,679,681,683,686,689,691],{"class":34,"line":35},[32,674,46],{"class":45},[32,676,50],{"class":49},[32,678,278],{"class":45},[32,680,90],{"class":45},[32,682,56],{"class":49},[32,684,685],{"class":45},"interface",[32,687,688],{"class":49},"{}]",[32,690,99],{"class":45},[32,692,693],{"class":49},"{}\n",[32,695,696,699,702,705,707,710],{"class":34,"line":42},[32,697,698],{"class":49},"m[",[32,700,701],{"class":115},"1",[32,703,704],{"class":49},"] ",[32,706,278],{"class":45},[32,708,709],{"class":115}," 1",[32,711,712],{"class":38},"      \u002F\u002F ок\n",[32,714,715,718,720,722,724,727,729,731],{"class":34,"line":68},[32,716,717],{"class":49},"m[[]",[32,719,99],{"class":45},[32,721,239],{"class":49},[32,723,701],{"class":115},[32,725,726],{"class":49},"}] ",[32,728,278],{"class":45},[32,730,709],{"class":115},[32,732,733],{"class":38}," \u002F\u002F panic: runtime error: hash of unhashable type []int\n",[14,735],{},[17,737,739],{"id":738},"map-не-потокобезопасен","Map не потокобезопасен",[11,741,742],{},"Это, пожалуй, самая популярная ловушка. Конкурентное чтение безопасно, но конкурентная запись (или запись + чтение одновременно) — это гонка данных и паника в рантайме:",[22,744,747],{"className":24,"code":745,"language":26,"meta":746,"style":27},"m := make(map[string]int)\n\n\u002F\u002F Паника: concurrent map writes\ngo func() { m[\"a\"] = 1 }()\ngo func() { m[\"b\"] = 2 }()\n","static",[29,748,749,771,775,780,802],{"__ignoreMap":27},[32,750,751,753,755,757,759,761,763,765,767,769],{"class":34,"line":35},[32,752,84],{"class":49},[32,754,87],{"class":45},[32,756,161],{"class":160},[32,758,164],{"class":49},[32,760,53],{"class":45},[32,762,56],{"class":49},[32,764,59],{"class":45},[32,766,62],{"class":49},[32,768,99],{"class":45},[32,770,177],{"class":49},[32,772,773],{"class":34,"line":42},[32,774,72],{"emptyLinePlaceholder":71},[32,776,777],{"class":34,"line":68},[32,778,779],{"class":38},"\u002F\u002F Паника: concurrent map writes\n",[32,781,782,784,787,790,793,795,797,799],{"class":34,"line":75},[32,783,26],{"class":45},[32,785,786],{"class":45}," func",[32,788,789],{"class":49},"() { m[",[32,791,792],{"class":108},"\"a\"",[32,794,704],{"class":49},[32,796,278],{"class":45},[32,798,709],{"class":115},[32,800,801],{"class":49}," }()\n",[32,803,804,806,808,810,813,815,817,820],{"class":34,"line":81},[32,805,26],{"class":45},[32,807,786],{"class":45},[32,809,789],{"class":49},[32,811,812],{"class":108},"\"b\"",[32,814,704],{"class":49},[32,816,278],{"class":45},[32,818,819],{"class":115}," 2",[32,821,801],{"class":49},[11,823,824,825,828],{},"Go 1.6 добавил детектор гонок в рантайм — при конкурентной записи программа упадёт с ",[29,826,827],{},"fatal error: concurrent map writes",". Это намеренное поведение: лучше явная паника, чем тихая порча данных.",[11,830,831],{},[522,832,833],{},"Три способа сделать map потокобезопасным:",[22,835,837],{"className":24,"code":836,"language":26,"meta":27,"style":27},"package main\n\nimport (\n    \"fmt\"\n    \"sync\"\n)\n\n\u002F\u002F 1. sync.Mutex — универсально\ntype SafeMapMu struct {\n    mu sync.Mutex\n    m  map[string]int\n}\n\nfunc (s *SafeMapMu) Set(k string, v int) {\n    s.mu.Lock()\n    defer s.mu.Unlock()\n    s.m[k] = v\n}\n\n\u002F\u002F 2. sync.RWMutex — если чтений много больше записей\ntype SafeMapRW struct {\n    mu sync.RWMutex\n    m  map[string]int\n}\n\nfunc (s *SafeMapRW) Get(k string) (int, bool) {\n    s.mu.RLock()\n    defer s.mu.RUnlock()\n    v, ok := s.m[k]\n    return v, ok\n}\n\nfunc main() {\n    \u002F\u002F 3. sync.Map — специализирован для случая \"много читателей,\n    \u002F\u002F редкие записи, стабильный набор ключей\"\n    var sm sync.Map\n    sm.Store(\"alice\", 42)\n    v, ok := sm.Load(\"alice\")\n    fmt.Println(v, ok)\n    sm.Delete(\"alice\")\n    sm.Range(func(k, v interface{}) bool {\n        fmt.Println(k, v)\n        return true \u002F\u002F false — прервать итерацию\n    })\n}\n",[29,838,839,847,851,859,870,879,883,887,892,906,919,934,938,942,983,994,1007,1016,1020,1025,1031,1043,1055,1070,1075,1080,1117,1127,1139,1150,1159,1164,1169,1180,1186,1192,1208,1227,1246,1256,1270,1300,1310,1322,1328],{"__ignoreMap":27},[32,840,841,844],{"class":34,"line":35},[32,842,843],{"class":45},"package",[32,845,846],{"class":160}," main\n",[32,848,849],{"class":34,"line":42},[32,850,72],{"emptyLinePlaceholder":71},[32,852,853,856],{"class":34,"line":68},[32,854,855],{"class":45},"import",[32,857,858],{"class":49}," (\n",[32,860,861,864,867],{"class":34,"line":75},[32,862,863],{"class":108},"    \"",[32,865,866],{"class":160},"fmt",[32,868,869],{"class":108},"\"\n",[32,871,872,874,877],{"class":34,"line":81},[32,873,863],{"class":108},[32,875,876],{"class":160},"sync",[32,878,869],{"class":108},[32,880,881],{"class":34,"line":105},[32,882,177],{"class":49},[32,884,885],{"class":34,"line":122},[32,886,72],{"emptyLinePlaceholder":71},[32,888,889],{"class":34,"line":136},[32,890,891],{"class":38},"\u002F\u002F 1. sync.Mutex — универсально\n",[32,893,894,897,900,903],{"class":34,"line":142},[32,895,896],{"class":45},"type",[32,898,899],{"class":160}," SafeMapMu",[32,901,902],{"class":45}," struct",[32,904,905],{"class":49}," {\n",[32,907,908,911,913,916],{"class":34,"line":147},[32,909,910],{"class":49},"    mu ",[32,912,876],{"class":160},[32,914,915],{"class":49},".",[32,917,918],{"class":160},"Mutex\n",[32,920,921,924,926,928,930,932],{"class":34,"line":153},[32,922,923],{"class":49},"    m  ",[32,925,53],{"class":45},[32,927,56],{"class":49},[32,929,59],{"class":45},[32,931,62],{"class":49},[32,933,65],{"class":45},[32,935,936],{"class":34,"line":180},[32,937,139],{"class":49},[32,939,940],{"class":34,"line":355},[32,941,72],{"emptyLinePlaceholder":71},[32,943,944,947,950,954,957,960,962,965,967,970,973,975,978,980],{"class":34,"line":360},[32,945,946],{"class":45},"func",[32,948,949],{"class":49}," (",[32,951,953],{"class":952},"s9osk","s ",[32,955,956],{"class":45},"*",[32,958,959],{"class":160},"SafeMapMu",[32,961,207],{"class":49},[32,963,964],{"class":160},"Set",[32,966,164],{"class":49},[32,968,969],{"class":952},"k",[32,971,972],{"class":45}," string",[32,974,201],{"class":49},[32,976,977],{"class":952},"v",[32,979,621],{"class":45},[32,981,982],{"class":49},") {\n",[32,984,985,988,991],{"class":34,"line":366},[32,986,987],{"class":49},"    s.mu.",[32,989,990],{"class":160},"Lock",[32,992,993],{"class":49},"()\n",[32,995,996,999,1002,1005],{"class":34,"line":385},[32,997,998],{"class":45},"    defer",[32,1000,1001],{"class":49}," s.mu.",[32,1003,1004],{"class":160},"Unlock",[32,1006,993],{"class":49},[32,1008,1009,1012,1014],{"class":34,"line":395},[32,1010,1011],{"class":49},"    s.m[k] ",[32,1013,278],{"class":45},[32,1015,281],{"class":49},[32,1017,1018],{"class":34,"line":412},[32,1019,139],{"class":49},[32,1021,1023],{"class":34,"line":1022},19,[32,1024,72],{"emptyLinePlaceholder":71},[32,1026,1028],{"class":34,"line":1027},20,[32,1029,1030],{"class":38},"\u002F\u002F 2. sync.RWMutex — если чтений много больше записей\n",[32,1032,1034,1036,1039,1041],{"class":34,"line":1033},21,[32,1035,896],{"class":45},[32,1037,1038],{"class":160}," SafeMapRW",[32,1040,902],{"class":45},[32,1042,905],{"class":49},[32,1044,1046,1048,1050,1052],{"class":34,"line":1045},22,[32,1047,910],{"class":49},[32,1049,876],{"class":160},[32,1051,915],{"class":49},[32,1053,1054],{"class":160},"RWMutex\n",[32,1056,1058,1060,1062,1064,1066,1068],{"class":34,"line":1057},23,[32,1059,923],{"class":49},[32,1061,53],{"class":45},[32,1063,56],{"class":49},[32,1065,59],{"class":45},[32,1067,62],{"class":49},[32,1069,65],{"class":45},[32,1071,1073],{"class":34,"line":1072},24,[32,1074,139],{"class":49},[32,1076,1078],{"class":34,"line":1077},25,[32,1079,72],{"emptyLinePlaceholder":71},[32,1081,1083,1085,1087,1089,1091,1094,1096,1099,1101,1103,1105,1108,1110,1112,1115],{"class":34,"line":1082},26,[32,1084,946],{"class":45},[32,1086,949],{"class":49},[32,1088,953],{"class":952},[32,1090,956],{"class":45},[32,1092,1093],{"class":160},"SafeMapRW",[32,1095,207],{"class":49},[32,1097,1098],{"class":160},"Get",[32,1100,164],{"class":49},[32,1102,969],{"class":952},[32,1104,972],{"class":45},[32,1106,1107],{"class":49},") (",[32,1109,99],{"class":45},[32,1111,201],{"class":49},[32,1113,1114],{"class":45},"bool",[32,1116,982],{"class":49},[32,1118,1120,1122,1125],{"class":34,"line":1119},27,[32,1121,987],{"class":49},[32,1123,1124],{"class":160},"RLock",[32,1126,993],{"class":49},[32,1128,1130,1132,1134,1137],{"class":34,"line":1129},28,[32,1131,998],{"class":45},[32,1133,1001],{"class":49},[32,1135,1136],{"class":160},"RUnlock",[32,1138,993],{"class":49},[32,1140,1142,1145,1147],{"class":34,"line":1141},29,[32,1143,1144],{"class":49},"    v, ok ",[32,1146,87],{"class":45},[32,1148,1149],{"class":49}," s.m[k]\n",[32,1151,1153,1156],{"class":34,"line":1152},30,[32,1154,1155],{"class":45},"    return",[32,1157,1158],{"class":49}," v, ok\n",[32,1160,1162],{"class":34,"line":1161},31,[32,1163,139],{"class":49},[32,1165,1167],{"class":34,"line":1166},32,[32,1168,72],{"emptyLinePlaceholder":71},[32,1170,1172,1174,1177],{"class":34,"line":1171},33,[32,1173,946],{"class":45},[32,1175,1176],{"class":160}," main",[32,1178,1179],{"class":49},"() {\n",[32,1181,1183],{"class":34,"line":1182},34,[32,1184,1185],{"class":38},"    \u002F\u002F 3. sync.Map — специализирован для случая \"много читателей,\n",[32,1187,1189],{"class":34,"line":1188},35,[32,1190,1191],{"class":38},"    \u002F\u002F редкие записи, стабильный набор ключей\"\n",[32,1193,1195,1198,1201,1203,1205],{"class":34,"line":1194},36,[32,1196,1197],{"class":45},"    var",[32,1199,1200],{"class":49}," sm ",[32,1202,876],{"class":160},[32,1204,915],{"class":49},[32,1206,1207],{"class":160},"Map\n",[32,1209,1211,1214,1217,1219,1221,1223,1225],{"class":34,"line":1210},37,[32,1212,1213],{"class":49},"    sm.",[32,1215,1216],{"class":160},"Store",[32,1218,164],{"class":49},[32,1220,242],{"class":108},[32,1222,201],{"class":49},[32,1224,116],{"class":115},[32,1226,177],{"class":49},[32,1228,1230,1232,1234,1237,1240,1242,1244],{"class":34,"line":1229},38,[32,1231,1144],{"class":49},[32,1233,87],{"class":45},[32,1235,1236],{"class":49}," sm.",[32,1238,1239],{"class":160},"Load",[32,1241,164],{"class":49},[32,1243,242],{"class":108},[32,1245,177],{"class":49},[32,1247,1249,1251,1253],{"class":34,"line":1248},39,[32,1250,342],{"class":49},[32,1252,345],{"class":160},[32,1254,1255],{"class":49},"(v, ok)\n",[32,1257,1259,1261,1264,1266,1268],{"class":34,"line":1258},40,[32,1260,1213],{"class":49},[32,1262,1263],{"class":160},"Delete",[32,1265,164],{"class":49},[32,1267,242],{"class":108},[32,1269,177],{"class":49},[32,1271,1273,1275,1278,1280,1282,1284,1286,1288,1290,1293,1296,1298],{"class":34,"line":1272},41,[32,1274,1213],{"class":49},[32,1276,1277],{"class":160},"Range",[32,1279,164],{"class":49},[32,1281,946],{"class":45},[32,1283,164],{"class":49},[32,1285,969],{"class":952},[32,1287,201],{"class":49},[32,1289,977],{"class":952},[32,1291,1292],{"class":45}," interface",[32,1294,1295],{"class":49},"{}) ",[32,1297,1114],{"class":45},[32,1299,905],{"class":49},[32,1301,1303,1306,1308],{"class":34,"line":1302},42,[32,1304,1305],{"class":49},"        fmt.",[32,1307,345],{"class":160},[32,1309,513],{"class":49},[32,1311,1313,1316,1319],{"class":34,"line":1312},43,[32,1314,1315],{"class":45},"        return",[32,1317,1318],{"class":115}," true",[32,1320,1321],{"class":38}," \u002F\u002F false — прервать итерацию\n",[32,1323,1325],{"class":34,"line":1324},44,[32,1326,1327],{"class":49},"    })\n",[32,1329,1331],{"class":34,"line":1330},45,[32,1332,139],{"class":49},[11,1334,1335,1338],{},[29,1336,1337],{},"sync.Map"," не является заменой обычного map с мьютексом по умолчанию. Он быстрее в конкретном сценарии: ключи добавляются один раз и потом только читаются. При частых записях разных ключей он медленнее из-за внутренних двух уровней хранения.",[14,1340],{},[17,1342,1344],{"id":1343},"старая-реализация-map-до-go-124","Старая реализация map (до Go 1.24)",[11,1346,1347],{},"Чтобы понять, что изменилось, нужно сначала понять, как было.",[11,1349,1350,1351,542],{},"До Go 1.24 map реализовывался как ",[522,1352,1353],{},"хэш-таблица с цепочками через бакеты",[1355,1356,1357,1361,1368,1375],"ul",{},[1358,1359,1360],"li",{},"Данные хранятся в массиве бакетов, каждый бакет вмещает ровно 8 пар ключ-значение",[1358,1362,1363,1364,1367],{},"У каждого бакета есть ",[29,1365,1366],{},"tophash"," — массив из 8 байт, где каждый байт хранит старшие 8 бит хэша ключа",[1358,1369,1370,1371,1374],{},"При коллизии (бакет переполнен) создаётся ",[522,1372,1373],{},"overflow bucket"," — связный список дополнительных бакетов",[1358,1376,1377,1378,1381],{},"Максимальный load factor: ",[522,1379,1380],{},"6.5"," элементов на бакет",[22,1383,1388],{"className":1384,"code":1386,"language":1387},[1385],"language-text","Бакет (старый):\n┌─────────────────────────────────────────────┐\n│ tophash: [h1, h2, h3, h4, h5, h6, h7, h8] │  8 байт\n│ keys:    [k1, k2, k3, k4, k5, k6, k7, k8] │  8 × sizeof(K)\n│ values:  [v1, v2, v3, v4, v5, v6, v7, v8] │  8 × sizeof(V)\n│ overflow: *bucket                           │  указатель на след. бакет\n└─────────────────────────────────────────────┘\n","text",[29,1389,1386],{"__ignoreMap":27},[11,1391,1392],{},[522,1393,1394],{},"Проблемы старой реализации:",[11,1396,1397,1398,1401],{},"Поиск ключа требовал пройти по цепочке overflow buckets, каждый из которых находится в другом месте памяти. Это ",[522,1399,1400],{},"pointer chasing"," — прыжки по куче, убивающие CPU cache. При большом количестве коллизий производительность деградировала, а tail latency при росте таблицы (когда она удваивается и перехеширует все элементы разом) могла быть заметна в latency-sensitive сервисах.",[14,1403],{},[17,1405,1407],{"id":1406},"swiss-map-новая-реализация-в-go-124","Swiss Map — новая реализация в Go 1.24",[11,1409,1410,1411,1414],{},"В Go 1.24 map полностью переписан на основе ",[522,1412,1413],{},"Swiss Tables"," — дизайна хэш-таблицы, разработанного в Google в 2017 году для C++ библиотеки Abseil и доказавшего свою эффективность. Название \"Swiss\" — не случайное: аббревиатура Closed Hashing — CH, что совпадает с кодом Швейцарии.",[212,1416,1418],{"id":1417},"структура-группы-и-control-word","Структура: группы и control word",[11,1420,1421,1422,1425,1426,542],{},"Вместо бакетов с overflow — ",[522,1423,1424],{},"группы"," (groups), каждая из которых содержит ровно 8 слотов и 64-битное ",[522,1427,1428],{},"control word",[22,1430,1433],{"className":1431,"code":1432,"language":1387},[1385],"Группа в Swiss Map:\n┌────────────────────────────────────────────────────────────────┐\n│ control word: [b0, b1, b2, b3, b4, b5, b6, b7]  ← 8 байт     │\n│                                                                 │\n│ slots: [kv0, kv1, kv2, kv3, kv4, kv5, kv6, kv7]              │\n│         key+value хранятся вместе → cache locality             │\n└────────────────────────────────────────────────────────────────┘\n",[29,1434,1432],{"__ignoreMap":27},[11,1436,1437],{},"Каждый байт control word соответствует одному слоту и кодирует его состояние:",[1355,1439,1440,1446],{},[1358,1441,1442,1443,1445],{},"Старший бит (",[29,1444,701],{},") — слот пуст или удалён",[1358,1447,1448,1449,1452],{},"Если старший бит ",[29,1450,1451],{},"0"," — слот занят, и оставшиеся 7 бит хранят младшие биты хэша ключа (h2)",[11,1454,1455],{},"Хэш ключа делится на две части:",[1355,1457,1458,1464],{},[1358,1459,1460,1463],{},[522,1461,1462],{},"h1"," (старшие 57 бит) — определяет, в какую группу попадёт элемент",[1358,1465,1466,1468],{},[522,1467,17],{}," (младшие 7 бит) — хранится в control word для быстрого отсева",[212,1470,1472],{"id":1471},"поиск-через-simd","Поиск через SIMD",[11,1474,1475],{},"Именно здесь Swiss Map становится принципиально быстрее. При поиске ключа происходит следующее:",[1477,1478,1479,1482,1485],"ol",{},[1358,1480,1481],{},"Вычисляем хэш ключа, делим на h1 и h2",[1358,1483,1484],{},"По h1 находим нужную группу",[1358,1486,1487,1488],{},"Берём control word группы (8 байт) и ",[522,1489,1490],{},"сравниваем h2 сразу со всеми 8 байтами одновременно",[11,1492,1493,1494,1497],{},"Шаг 3 — это ",[522,1495,1496],{},"SIMD"," (Single Instruction, Multiple Data). На процессорах amd64 это делается одной инструкцией SSE3, которая за один такт сравнивает 8 байт. В результате мы получаем битовую маску: какие слоты потенциально содержат наш ключ.",[22,1499,1502],{"className":1500,"code":1501,"language":1387},[1385],"h2 нашего ключа:  [42, 42, 42, 42, 42, 42, 42, 42]\ncontrol word:     [42,  7, 99, 42,  0, 13, 42,  1]\n                   ↑              ↑         ↑\n                   совпадение     совпадение  совпадение → проверяем только эти слоты\n",[29,1503,1501],{"__ignoreMap":27},[11,1505,1506],{},"Только для слотов с совпадением h2 мы сравниваем полный ключ. Вероятность ложного срабатывания — 1\u002F128 (7 бит хэша), так что в большинстве случаев проверяется 0-1 слот.",[11,1508,1509,1510,1513],{},"На платформах без аппаратного SIMD Go применяет ",[522,1511,1512],{},"SWAR"," (SIMD Within A Register) — математически эквивалентный трюк с XOR и битовыми операциями, который обрабатывает все 8 байт за одну арифметическую операцию. Аппаратный SIMD на arm64 пока не реализован, но это уже запланировано.",[212,1515,1517],{"id":1516},"extendible-hashing-вместо-глобального-удвоения","Extendible hashing вместо глобального удвоения",[11,1519,1520,1521,1524],{},"Старый map при росте удваивал ",[522,1522,1523],{},"всю"," таблицу разом — все элементы перехешировались в одном вызове. Для большой таблицы это могло занять десятки миллисекунд.",[11,1526,1527,1528,1531,1532,1535],{},"Swiss Map ограничивает одну таблицу ",[522,1529,1530],{},"128 группами (1024 слота)",". При переполнении таблица ",[522,1533,1534],{},"делится"," (splitting), а не удваивается глобально — через механизм extendible hashing: директория указателей на независимые таблицы, которые растут поодиночке. Пиковая задержка на вставку становится предсказуемой и ограниченной.",[212,1537,1539],{"id":1538},"итог-что-изменилось-в-числах","Итог: что изменилось в числах",[1541,1542,1543,1558],"table",{},[1544,1545,1546],"thead",{},[1547,1548,1549,1552,1555],"tr",{},[1550,1551],"th",{},[1550,1553,1554],{},"Go ≤ 1.23",[1550,1556,1557],{},"Go 1.24",[1559,1560,1561,1573,1584,1595,1606,1617,1628],"tbody",{},[1547,1562,1563,1567,1570],{},[1564,1565,1566],"td",{},"Структура",[1564,1568,1569],{},"бакеты + overflow (chaining)",[1564,1571,1572],{},"группы + control word (open addressing)",[1547,1574,1575,1578,1581],{},[1564,1576,1577],{},"Поиск h2",[1564,1579,1580],{},"последовательный, по одному",[1564,1582,1583],{},"SIMD: 8 сравнений за 1 инструкцию",[1547,1585,1586,1589,1592],{},[1564,1587,1588],{},"Max load factor",[1564,1590,1591],{},"6.5 \u002F 8 ≈ 81%",[1564,1593,1594],{},"7 \u002F 8 = 87.5%",[1547,1596,1597,1600,1603],{},[1564,1598,1599],{},"Рост таблицы",[1564,1601,1602],{},"глобальное удвоение",[1564,1604,1605],{},"локальное splitting",[1547,1607,1608,1611,1614],{},[1564,1609,1610],{},"Cache locality",[1564,1612,1613],{},"pointer chasing в overflow",[1564,1615,1616],{},"ключ + значение рядом в памяти",[1547,1618,1619,1622,1625],{},[1564,1620,1621],{},"Скорость операций",[1564,1623,1624],{},"baseline",[1564,1626,1627],{},"до +60% в микробенчмарках",[1547,1629,1630,1633,1635],{},[1564,1631,1632],{},"Потребление памяти",[1564,1634,1624],{},[1564,1636,1637],{},"−30–70% на больших map",[14,1639],{},[17,1641,1643],{"id":1642},"нюансы-поведения-map","Нюансы поведения map",[212,1645,1647],{"id":1646},"модификация-во-время-итерации","Модификация во время итерации",[11,1649,1650,1651,542],{},"Спецификация Go явно разрешает изменять map во время ",[29,1652,1653],{},"range",[22,1655,1657],{"className":24,"code":1656,"language":26,"meta":27,"style":27},"m := map[string]int{\"a\": 1, \"b\": 2, \"c\": 3}\n\nfor k := range m {\n    if k == \"b\" {\n        delete(m, \"b\") \u002F\u002F безопасно — удалённый ключ не появится\n        m[\"d\"] = 4     \u002F\u002F новый ключ может появиться или нет в этом range\n    }\n}\n",[29,1658,1659,1703,1707,1720,1734,1748,1766,1771],{"__ignoreMap":27},[32,1660,1661,1663,1665,1667,1669,1671,1673,1675,1677,1679,1681,1683,1685,1687,1689,1692,1694,1697,1699,1701],{"class":34,"line":35},[32,1662,84],{"class":49},[32,1664,87],{"class":45},[32,1666,90],{"class":45},[32,1668,56],{"class":49},[32,1670,59],{"class":45},[32,1672,62],{"class":49},[32,1674,99],{"class":45},[32,1676,239],{"class":49},[32,1678,792],{"class":108},[32,1680,112],{"class":49},[32,1682,701],{"class":115},[32,1684,201],{"class":49},[32,1686,812],{"class":108},[32,1688,112],{"class":49},[32,1690,1691],{"class":115},"2",[32,1693,201],{"class":49},[32,1695,1696],{"class":108},"\"c\"",[32,1698,112],{"class":49},[32,1700,587],{"class":115},[32,1702,139],{"class":49},[32,1704,1705],{"class":34,"line":42},[32,1706,72],{"emptyLinePlaceholder":71},[32,1708,1709,1711,1714,1716,1718],{"class":34,"line":68},[32,1710,493],{"class":45},[32,1712,1713],{"class":49}," k ",[32,1715,87],{"class":45},[32,1717,501],{"class":45},[32,1719,504],{"class":49},[32,1721,1722,1725,1727,1729,1732],{"class":34,"line":75},[32,1723,1724],{"class":45},"    if",[32,1726,1713],{"class":49},[32,1728,541],{"class":45},[32,1730,1731],{"class":108}," \"b\"",[32,1733,905],{"class":49},[32,1735,1736,1739,1741,1743,1745],{"class":34,"line":81},[32,1737,1738],{"class":160},"        delete",[32,1740,476],{"class":49},[32,1742,812],{"class":108},[32,1744,207],{"class":49},[32,1746,1747],{"class":38},"\u002F\u002F безопасно — удалённый ключ не появится\n",[32,1749,1750,1753,1756,1758,1760,1763],{"class":34,"line":105},[32,1751,1752],{"class":49},"        m[",[32,1754,1755],{"class":108},"\"d\"",[32,1757,704],{"class":49},[32,1759,278],{"class":45},[32,1761,1762],{"class":115}," 4",[32,1764,1765],{"class":38},"     \u002F\u002F новый ключ может появиться или нет в этом range\n",[32,1767,1768],{"class":34,"line":122},[32,1769,1770],{"class":49},"    }\n",[32,1772,1773],{"class":34,"line":136},[32,1774,139],{"class":49},[11,1776,1777],{},"Правила: удалённые в ходе итерации ключи точно не появятся, обновлённые значения будут актуальны, новые ключи — могут встретиться или нет (не гарантировано). Swiss Map сохраняет эту семантику, хотя реализовать её поверх open-addressed таблицы было нетривиально.",[212,1779,1781],{"id":1780},"запись-в-nil-map-паника","Запись в nil map — паника",[22,1783,1785],{"className":24,"code":1784,"language":26,"meta":27,"style":27},"var m map[string]int\nv := m[\"key\"]  \u002F\u002F 0 — безопасно\nm[\"key\"] = 1   \u002F\u002F panic: assignment to entry in nil map\n",[29,1786,1787,1803,1819],{"__ignoreMap":27},[32,1788,1789,1791,1793,1795,1797,1799,1801],{"class":34,"line":35},[32,1790,46],{"class":45},[32,1792,50],{"class":49},[32,1794,53],{"class":45},[32,1796,56],{"class":49},[32,1798,59],{"class":45},[32,1800,62],{"class":49},[32,1802,65],{"class":45},[32,1804,1805,1807,1809,1811,1814,1816],{"class":34,"line":42},[32,1806,257],{"class":49},[32,1808,87],{"class":45},[32,1810,262],{"class":49},[32,1812,1813],{"class":108},"\"key\"",[32,1815,379],{"class":49},[32,1817,1818],{"class":38},"\u002F\u002F 0 — безопасно\n",[32,1820,1821,1823,1825,1827,1829,1831],{"class":34,"line":68},[32,1822,698],{"class":49},[32,1824,1813],{"class":108},[32,1826,704],{"class":49},[32,1828,278],{"class":45},[32,1830,709],{"class":115},[32,1832,1833],{"class":38},"   \u002F\u002F panic: assignment to entry in nil map\n",[212,1835,1837],{"id":1836},"элементы-map-non-addressable","Элементы map — non-addressable",[22,1839,1841],{"className":24,"code":1840,"language":26,"meta":27,"style":27},"type Point struct{ X, Y int }\nm := map[string]Point{\"a\": {1, 2}}\n\n\u002F\u002F m[\"a\"].X = 10 \u002F\u002F Ошибка компиляции: cannot assign to struct field in map\n\n\u002F\u002F Правильно\np := m[\"a\"]\np.X = 10\nm[\"a\"] = p\n",[29,1842,1843,1860,1893,1897,1905,1909,1914,1927,1937],{"__ignoreMap":27},[32,1844,1845,1847,1850,1852,1855,1857],{"class":34,"line":35},[32,1846,896],{"class":45},[32,1848,1849],{"class":160}," Point",[32,1851,902],{"class":45},[32,1853,1854],{"class":49},"{ X, Y ",[32,1856,99],{"class":45},[32,1858,1859],{"class":49}," }\n",[32,1861,1862,1864,1866,1868,1870,1872,1874,1877,1879,1881,1884,1886,1888,1890],{"class":34,"line":42},[32,1863,84],{"class":49},[32,1865,87],{"class":45},[32,1867,90],{"class":45},[32,1869,56],{"class":49},[32,1871,59],{"class":45},[32,1873,62],{"class":49},[32,1875,1876],{"class":160},"Point",[32,1878,239],{"class":49},[32,1880,792],{"class":108},[32,1882,1883],{"class":49},": {",[32,1885,701],{"class":115},[32,1887,201],{"class":49},[32,1889,1691],{"class":115},[32,1891,1892],{"class":49},"}}\n",[32,1894,1895],{"class":34,"line":68},[32,1896,72],{"emptyLinePlaceholder":71},[32,1898,1899,1902],{"class":34,"line":75},[32,1900,1901],{"class":38},"\u002F\u002F m[\"a\"].X = 10",[32,1903,1904],{"class":38}," \u002F\u002F Ошибка компиляции: cannot assign to struct field in map\n",[32,1906,1907],{"class":34,"line":81},[32,1908,72],{"emptyLinePlaceholder":71},[32,1910,1911],{"class":34,"line":105},[32,1912,1913],{"class":38},"\u002F\u002F Правильно\n",[32,1915,1916,1919,1921,1923,1925],{"class":34,"line":122},[32,1917,1918],{"class":49},"p ",[32,1920,87],{"class":45},[32,1922,262],{"class":49},[32,1924,792],{"class":108},[32,1926,329],{"class":49},[32,1928,1929,1932,1934],{"class":34,"line":136},[32,1930,1931],{"class":49},"p.X ",[32,1933,278],{"class":45},[32,1935,1936],{"class":115}," 10\n",[32,1938,1939,1941,1943,1945,1947],{"class":34,"line":142},[32,1940,698],{"class":49},[32,1942,792],{"class":108},[32,1944,704],{"class":49},[32,1946,278],{"class":45},[32,1948,1949],{"class":49}," p\n",[11,1951,1952],{},"Это следствие того, что map может перераспределить память при росте, и адрес элемента может измениться — Go не позволяет хранить указатель на нестабильный адрес.",[14,1954],{},[17,1956,1958],{"id":1957},"производительность-практические-советы","Производительность: практические советы",[11,1960,1961,1964,1965,1968],{},[522,1962,1963],{},"Задайте начальную ёмкость, если размер известен."," ",[29,1966,1967],{},"make(map[K]V, n)"," — это hint, позволяющий избежать реаллокаций при росте:",[22,1970,1972],{"className":24,"code":1971,"language":26,"meta":27,"style":27},"\u002F\u002F Плохо — много реаллокаций при росте\nm := make(map[string]int)\nfor _, item := range items {\n    m[item.Key] = item.Value\n}\n\n\u002F\u002F Хорошо — одна аллокация\nm := make(map[string]int, len(items))\nfor _, item := range items {\n    m[item.Key] = item.Value\n}\n",[29,1973,1974,1979,2001,2015,2025,2029,2033,2038,2066,2078,2086],{"__ignoreMap":27},[32,1975,1976],{"class":34,"line":35},[32,1977,1978],{"class":38},"\u002F\u002F Плохо — много реаллокаций при росте\n",[32,1980,1981,1983,1985,1987,1989,1991,1993,1995,1997,1999],{"class":34,"line":42},[32,1982,84],{"class":49},[32,1984,87],{"class":45},[32,1986,161],{"class":160},[32,1988,164],{"class":49},[32,1990,53],{"class":45},[32,1992,56],{"class":49},[32,1994,59],{"class":45},[32,1996,62],{"class":49},[32,1998,99],{"class":45},[32,2000,177],{"class":49},[32,2002,2003,2005,2008,2010,2012],{"class":34,"line":68},[32,2004,493],{"class":45},[32,2006,2007],{"class":49}," _, item ",[32,2009,87],{"class":45},[32,2011,501],{"class":45},[32,2013,2014],{"class":49}," items {\n",[32,2016,2017,2020,2022],{"class":34,"line":75},[32,2018,2019],{"class":49},"    m[item.Key] ",[32,2021,278],{"class":45},[32,2023,2024],{"class":49}," item.Value\n",[32,2026,2027],{"class":34,"line":81},[32,2028,139],{"class":49},[32,2030,2031],{"class":34,"line":105},[32,2032,72],{"emptyLinePlaceholder":71},[32,2034,2035],{"class":34,"line":122},[32,2036,2037],{"class":38},"\u002F\u002F Хорошо — одна аллокация\n",[32,2039,2040,2042,2044,2046,2048,2050,2052,2054,2056,2058,2060,2063],{"class":34,"line":136},[32,2041,84],{"class":49},[32,2043,87],{"class":45},[32,2045,161],{"class":160},[32,2047,164],{"class":49},[32,2049,53],{"class":45},[32,2051,56],{"class":49},[32,2053,59],{"class":45},[32,2055,62],{"class":49},[32,2057,99],{"class":45},[32,2059,201],{"class":49},[32,2061,2062],{"class":160},"len",[32,2064,2065],{"class":49},"(items))\n",[32,2067,2068,2070,2072,2074,2076],{"class":34,"line":142},[32,2069,493],{"class":45},[32,2071,2007],{"class":49},[32,2073,87],{"class":45},[32,2075,501],{"class":45},[32,2077,2014],{"class":49},[32,2079,2080,2082,2084],{"class":34,"line":147},[32,2081,2019],{"class":49},[32,2083,278],{"class":45},[32,2085,2024],{"class":49},[32,2087,2088],{"class":34,"line":153},[32,2089,139],{"class":49},[11,2091,2092,2095],{},[522,2093,2094],{},"Используйте struct{} для set-семантики."," Если нужен только факт присутствия ключа:",[22,2097,2099],{"className":24,"code":2098,"language":26,"meta":27,"style":27},"seen := make(map[string]struct{})\nseen[\"alice\"] = struct{}{}\n_, exists := seen[\"alice\"]\n",[29,2100,2101,2125,2141],{"__ignoreMap":27},[32,2102,2103,2106,2108,2110,2112,2114,2116,2118,2120,2122],{"class":34,"line":35},[32,2104,2105],{"class":49},"seen ",[32,2107,87],{"class":45},[32,2109,161],{"class":160},[32,2111,164],{"class":49},[32,2113,53],{"class":45},[32,2115,56],{"class":49},[32,2117,59],{"class":45},[32,2119,62],{"class":49},[32,2121,607],{"class":45},[32,2123,2124],{"class":49},"{})\n",[32,2126,2127,2130,2132,2134,2136,2138],{"class":34,"line":42},[32,2128,2129],{"class":49},"seen[",[32,2131,242],{"class":108},[32,2133,704],{"class":49},[32,2135,278],{"class":45},[32,2137,902],{"class":45},[32,2139,2140],{"class":49},"{}{}\n",[32,2142,2143,2146,2148,2151,2153],{"class":34,"line":68},[32,2144,2145],{"class":49},"_, exists ",[32,2147,87],{"class":45},[32,2149,2150],{"class":49}," seen[",[32,2152,242],{"class":108},[32,2154,329],{"class":49},[11,2156,2157,2160,2161,915],{},[29,2158,2159],{},"struct{}"," не занимает памяти (zero-size type) — экономия по сравнению с ",[29,2162,2163],{},"map[string]bool",[14,2165],{},[17,2167,2169],{"id":2168},"вопросы-на-собеседовании","Вопросы на собеседовании",[11,2171,2172,2175,2178],{},[522,2173,2174],{},"Q: Что такое map в Go внутри? Опишите структуру.",[2176,2177],"br",{},"\nA: До Go 1.24 — хэш-таблица с бакетами по 8 элементов и overflow buckets в виде связного списка при коллизиях. С Go 1.24 — Swiss Table: группы из 8 слотов с 64-битным control word, open addressing с линейным пробированием, extendible hashing для роста.",[11,2180,2181,2184,2186,2187,2189],{},[522,2182,2183],{},"Q: Почему порядок итерации по map не гарантирован?",[2176,2185],{},"\nA: Намеренная рандомизация, введённая в Go 1.0, чтобы разработчики не полагались на случайно воспроизводимый порядок. При каждом ",[29,2188,1653],{}," начальная позиция итерации выбирается случайно.",[11,2191,2192,2195,2197,2198,2200],{},[522,2193,2194],{},"Q: Почему map не потокобезопасен? Что будет при конкурентной записи?",[2176,2196],{},"\nA: Map не защищён мьютексом для производительности. Конкурентная запись (или запись + чтение) — это data race, которая в Go 1.6+ детектируется в рантайме и вызывает ",[29,2199,827],{},". Решения: sync.Mutex, sync.RWMutex или sync.Map.",[11,2202,2203,2206,2208,2209,2211],{},[522,2204,2205],{},"Q: Чем sync.Map отличается от map с мьютексом? Когда что использовать?",[2176,2207],{},"\nA: ",[29,2210,1337],{}," оптимизирован для сценария \"ключи записываются редко, читаются часто\". Внутри у него два уровня хранения: read-only (без блокировки) и dirty (с блокировкой). При частых записях разных ключей он медленнее обычного map с мьютексом из-за накладных расходов на синхронизацию двух уровней.",[11,2213,2214,2217,2219,2220,2222],{},[522,2215,2216],{},"Q: Какие типы могут быть ключами map?",[2176,2218],{},"\nA: Только comparable типы — те, для которых определён ",[29,2221,541],{},". Базовые типы, массивы, структуры из comparable полей. Нельзя: слайсы, map, функции. Интерфейсы можно, но паника в рантайме, если реальный тип не comparable.",[11,2224,2225,2228,2230],{},[522,2226,2227],{},"Q: Что такое Swiss Table и чем она лучше старой реализации?",[2176,2229],{},"\nA: Swiss Table — это open-addressed хэш-таблица с control word на группу. Ключевое улучшение — поиск через SIMD: 7 бит хэша ключа (h2) сравниваются со всеми 8 слотами группы одной процессорной инструкцией. Это устраняет pointer chasing от overflow buckets, улучшает cache locality и даёт до 60% ускорения операций.",[11,2232,2233,2236,2238],{},[522,2234,2235],{},"Q: Что такое SIMD в контексте Swiss Map?",[2176,2237],{},"\nA: Single Instruction, Multiple Data — одна CPU инструкция, обрабатывающая несколько данных одновременно. Swiss Map использует SSE3 на amd64: control word группы (8 байт) сравнивается с h2 ключа за один такт, возвращая битовую маску совпавших слотов. На платформах без аппаратного SIMD используется SWAR — тот же эффект через XOR и битовую арифметику.",[11,2240,2241,2244,2246],{},[522,2242,2243],{},"Q: Можно ли взять адрес элемента map? Почему?",[2176,2245],{},"\nA: Нет. Элементы map non-addressable — при росте таблицы Go может переместить данные в памяти, и старый указатель стал бы невалидным. Чтобы изменить поле в структуре внутри map, нужно достать значение, изменить копию, положить обратно.",[11,2248,2249,2256,2208,2258,2260,2261,2264,2265,2268],{},[522,2250,2251,2252,2255],{},"Q: Чем ",[29,2253,2254],{},"nil","-map отличается от пустой map?",[2176,2257],{},[29,2259,2254],{},"-map (",[29,2262,2263],{},"var m map[string]int",") — чтение возвращает zero value, запись вызывает панику. Пустая map (",[29,2266,2267],{},"make(map[string]int)",") — готова к использованию. Длина обоих — 0.",[11,2270,2271,2274,2276,2277,2280,2281,2284,2285,2288,2289,2291],{},[522,2272,2273],{},"Q: Как сделать map потокобезопасным для сценария \"много читателей, редкие записи\"?",[2176,2275],{},"\nA: Через ",[29,2278,2279],{},"sync.RWMutex",": читатели берут ",[29,2282,2283],{},"RLock()"," (не блокируют друг друга), писатель берёт ",[29,2286,2287],{},"Lock()"," (эксклюзивный доступ). Как альтернатива — ",[29,2290,1337],{},", который внутренне реализует схожую стратегию с atomic-операциями на read-path.",[11,2293,2294,2300,2302,2303,2305],{},[522,2295,2296,2297,2299],{},"Q: Что произойдёт, если удалить ключ во время ",[29,2298,1653],{}," по map?",[2176,2301],{},"\nA: Безопасно — удалённый ключ гарантированно не появится в текущей итерации. Добавление новых ключей во время ",[29,2304,1653],{}," допустимо, но они могут появиться или не появиться — это неопределённое поведение (в рамках спецификации).",[14,2307],{},[17,2309,2311],{"id":2310},"практика","Практика",[2313,2314,2317,2320,2380,2395],"quiz",{"answer":1691,"id":2315,"xp":2316},"basics-map-q1","10",[11,2318,2319],{},"Что выведет код?",[22,2321,2323],{"className":24,"code":2322,"language":26,"meta":27,"style":27},"m := map[string]int{\"a\": 1, \"b\": 2}\nv := m[\"c\"]\nfmt.Println(v)\n",[29,2324,2325,2359,2371],{"__ignoreMap":27},[32,2326,2327,2329,2331,2333,2335,2337,2339,2341,2343,2345,2347,2349,2351,2353,2355,2357],{"class":34,"line":35},[32,2328,84],{"class":49},[32,2330,87],{"class":45},[32,2332,90],{"class":45},[32,2334,56],{"class":49},[32,2336,59],{"class":45},[32,2338,62],{"class":49},[32,2340,99],{"class":45},[32,2342,239],{"class":49},[32,2344,792],{"class":108},[32,2346,112],{"class":49},[32,2348,701],{"class":115},[32,2350,201],{"class":49},[32,2352,812],{"class":108},[32,2354,112],{"class":49},[32,2356,1691],{"class":115},[32,2358,139],{"class":49},[32,2360,2361,2363,2365,2367,2369],{"class":34,"line":42},[32,2362,257],{"class":49},[32,2364,87],{"class":45},[32,2366,262],{"class":49},[32,2368,1696],{"class":108},[32,2370,329],{"class":49},[32,2372,2373,2376,2378],{"class":34,"line":68},[32,2374,2375],{"class":49},"fmt.",[32,2377,345],{"class":160},[32,2379,348],{"class":49},[2381,2382,2383],"template",{"v-slot:options":27},[1355,2384,2385,2388,2390,2392],{},[1358,2386,2387],{},"panic: key not found",[1358,2389,1451],{},[1358,2391,2254],{},[1358,2393,2394],{},"ошибка компиляции",[2381,2396,2397],{"v-slot:explanation":27},[11,2398,2399,2400,2403,2404,2406,2407,2409,2410,915],{},"Чтение несуществующего ключа из map ",[522,2401,2402],{},"никогда не паникует",". Возвращается zero value типа значения — для ",[29,2405,99],{}," это ",[29,2408,1451],{},". Чтобы отличить \"нет ключа\" от \"значение равно 0\" — используй двухзначную форму: ",[29,2411,2412],{},"v, ok := m[\"c\"]",[2313,2414,2416,2423,2447],{"answer":701,"id":2415,"xp":2316},"basics-map-q2",[11,2417,2418,2419,2422],{},"Как правильно проверить, существует ли ключ ",[29,2420,2421],{},"\"player\""," в map?",[2381,2424,2425],{"v-slot:options":27},[1355,2426,2427,2432,2437,2442],{},[1358,2428,2429],{},[29,2430,2431],{},"if count, ok := m[\"player\"]; ok { ... }",[1358,2433,2434],{},[29,2435,2436],{},"if m[\"player\"] != 0 { ... }",[1358,2438,2439],{},[29,2440,2441],{},"if m[\"player\"] != nil { ... }",[1358,2443,2444],{},[29,2445,2446],{},"if len(m[\"player\"]) > 0 { ... }",[2381,2448,2449],{"v-slot:explanation":27},[11,2450,2451,2452,2455,2456,2459,2460,2463,2464,2466,2467,2470],{},"Единственный надёжный способ — двухзначная форма ",[29,2453,2454],{},"v, ok := m[key]",". Проверка ",[29,2457,2458],{},"!= 0"," ложна: ключ может существовать со значением 0. ",[29,2461,2462],{},"!= nil"," — ошибка компиляции для ",[29,2465,99],{},". Двухзначная форма возвращает ",[29,2468,2469],{},"ok = false"," именно когда ключа нет.",[2472,2473,2477,2480,2651],"predict",{"answer":2474,"id":2475,"xp":2476},"3\\n1\\n2","basics-map-p1","15",[11,2478,2479],{},"Что выведет программа? Определи значения для каждого ключа.",[2381,2481,2482],{"v-slot:code":27},[22,2483,2485],{"className":24,"code":2484,"language":26,"meta":27,"style":27},"package main\n\nimport \"fmt\"\n\nfunc main() {\n    votes := []string{\"alice\", \"bob\", \"alice\", \"eve\", \"alice\", \"eve\"}\n    counter := make(map[string]int)\n    for _, name := range votes {\n        counter[name]++\n    }\n    fmt.Println(counter[\"alice\"])\n    fmt.Println(counter[\"bob\"])\n    fmt.Println(counter[\"eve\"])\n}\n",[29,2486,2487,2493,2497,2508,2512,2520,2559,2582,2597,2605,2609,2623,2635,2647],{"__ignoreMap":27},[32,2488,2489,2491],{"class":34,"line":35},[32,2490,843],{"class":45},[32,2492,846],{"class":160},[32,2494,2495],{"class":34,"line":42},[32,2496,72],{"emptyLinePlaceholder":71},[32,2498,2499,2501,2504,2506],{"class":34,"line":68},[32,2500,855],{"class":45},[32,2502,2503],{"class":108}," \"",[32,2505,866],{"class":160},[32,2507,869],{"class":108},[32,2509,2510],{"class":34,"line":75},[32,2511,72],{"emptyLinePlaceholder":71},[32,2513,2514,2516,2518],{"class":34,"line":81},[32,2515,946],{"class":45},[32,2517,1176],{"class":160},[32,2519,1179],{"class":49},[32,2521,2522,2525,2527,2530,2532,2534,2536,2538,2540,2542,2544,2546,2549,2551,2553,2555,2557],{"class":34,"line":105},[32,2523,2524],{"class":49},"    votes ",[32,2526,87],{"class":45},[32,2528,2529],{"class":49}," []",[32,2531,59],{"class":45},[32,2533,239],{"class":49},[32,2535,242],{"class":108},[32,2537,201],{"class":49},[32,2539,458],{"class":108},[32,2541,201],{"class":49},[32,2543,242],{"class":108},[32,2545,201],{"class":49},[32,2547,2548],{"class":108},"\"eve\"",[32,2550,201],{"class":49},[32,2552,242],{"class":108},[32,2554,201],{"class":49},[32,2556,2548],{"class":108},[32,2558,139],{"class":49},[32,2560,2561,2564,2566,2568,2570,2572,2574,2576,2578,2580],{"class":34,"line":122},[32,2562,2563],{"class":49},"    counter ",[32,2565,87],{"class":45},[32,2567,161],{"class":160},[32,2569,164],{"class":49},[32,2571,53],{"class":45},[32,2573,56],{"class":49},[32,2575,59],{"class":45},[32,2577,62],{"class":49},[32,2579,99],{"class":45},[32,2581,177],{"class":49},[32,2583,2584,2587,2590,2592,2594],{"class":34,"line":136},[32,2585,2586],{"class":45},"    for",[32,2588,2589],{"class":49}," _, name ",[32,2591,87],{"class":45},[32,2593,501],{"class":45},[32,2595,2596],{"class":49}," votes {\n",[32,2598,2599,2602],{"class":34,"line":142},[32,2600,2601],{"class":49},"        counter[name]",[32,2603,2604],{"class":45},"++\n",[32,2606,2607],{"class":34,"line":147},[32,2608,1770],{"class":49},[32,2610,2611,2613,2615,2618,2620],{"class":34,"line":153},[32,2612,342],{"class":49},[32,2614,345],{"class":160},[32,2616,2617],{"class":49},"(counter[",[32,2619,242],{"class":108},[32,2621,2622],{"class":49},"])\n",[32,2624,2625,2627,2629,2631,2633],{"class":34,"line":180},[32,2626,342],{"class":49},[32,2628,345],{"class":160},[32,2630,2617],{"class":49},[32,2632,458],{"class":108},[32,2634,2622],{"class":49},[32,2636,2637,2639,2641,2643,2645],{"class":34,"line":355},[32,2638,342],{"class":49},[32,2640,345],{"class":160},[32,2642,2617],{"class":49},[32,2644,2548],{"class":108},[32,2646,2622],{"class":49},[32,2648,2649],{"class":34,"line":360},[32,2650,139],{"class":49},[2381,2652,2653],{"v-slot:hint":27},[11,2654,2655,2658],{},[29,2656,2657],{},"counter[name]++"," работает даже если ключа нет — сначала создаётся с zero value (0), затем инкрементируется. Подсчитай сколько раз каждое имя встречается в слайсе.",[2660,2661,2665,2676,2831],"code-task",{"expected":2662,"id":2663,"xp":2664},"alice\\nb","basics-map-ct1","20",[11,2666,2667,2668,2671,2672,2675],{},"Напиши функцию ",[29,2669,2670],{},"firstDuplicate",", которая принимает ",[29,2673,2674],{},"[]string"," и возвращает первый элемент, встретившийся дважды. Если дублей нет — верни пустую строку. Используй map для отслеживания встреченных элементов.",[2381,2677,2678],{"v-slot:template":27},[22,2679,2681],{"className":24,"code":2680,"language":26,"meta":27,"style":27},"package main\n\nimport \"fmt\"\n\nfunc firstDuplicate(items []string) string {\n    \u002F\u002F твой код здесь\n    return \"\"\n}\n\nfunc main() {\n    fmt.Println(firstDuplicate([]string{\"alice\", \"bob\", \"alice\", \"eve\"}))\n    fmt.Println(firstDuplicate([]string{\"a\", \"b\", \"c\", \"b\", \"a\"}))\n}\n",[29,2682,2683,2689,2693,2703,2707,2729,2734,2741,2745,2749,2757,2791,2827],{"__ignoreMap":27},[32,2684,2685,2687],{"class":34,"line":35},[32,2686,843],{"class":45},[32,2688,846],{"class":160},[32,2690,2691],{"class":34,"line":42},[32,2692,72],{"emptyLinePlaceholder":71},[32,2694,2695,2697,2699,2701],{"class":34,"line":68},[32,2696,855],{"class":45},[32,2698,2503],{"class":108},[32,2700,866],{"class":160},[32,2702,869],{"class":108},[32,2704,2705],{"class":34,"line":75},[32,2706,72],{"emptyLinePlaceholder":71},[32,2708,2709,2711,2714,2716,2719,2721,2723,2725,2727],{"class":34,"line":81},[32,2710,946],{"class":45},[32,2712,2713],{"class":160}," firstDuplicate",[32,2715,164],{"class":49},[32,2717,2718],{"class":952},"items",[32,2720,2529],{"class":49},[32,2722,59],{"class":45},[32,2724,207],{"class":49},[32,2726,59],{"class":45},[32,2728,905],{"class":49},[32,2730,2731],{"class":34,"line":105},[32,2732,2733],{"class":38},"    \u002F\u002F твой код здесь\n",[32,2735,2736,2738],{"class":34,"line":122},[32,2737,1155],{"class":45},[32,2739,2740],{"class":108}," \"\"\n",[32,2742,2743],{"class":34,"line":136},[32,2744,139],{"class":49},[32,2746,2747],{"class":34,"line":142},[32,2748,72],{"emptyLinePlaceholder":71},[32,2750,2751,2753,2755],{"class":34,"line":147},[32,2752,946],{"class":45},[32,2754,1176],{"class":160},[32,2756,1179],{"class":49},[32,2758,2759,2761,2763,2765,2767,2770,2772,2774,2776,2778,2780,2782,2784,2786,2788],{"class":34,"line":153},[32,2760,342],{"class":49},[32,2762,345],{"class":160},[32,2764,164],{"class":49},[32,2766,2670],{"class":160},[32,2768,2769],{"class":49},"([]",[32,2771,59],{"class":45},[32,2773,239],{"class":49},[32,2775,242],{"class":108},[32,2777,201],{"class":49},[32,2779,458],{"class":108},[32,2781,201],{"class":49},[32,2783,242],{"class":108},[32,2785,201],{"class":49},[32,2787,2548],{"class":108},[32,2789,2790],{"class":49},"}))\n",[32,2792,2793,2795,2797,2799,2801,2803,2805,2807,2809,2811,2813,2815,2817,2819,2821,2823,2825],{"class":34,"line":180},[32,2794,342],{"class":49},[32,2796,345],{"class":160},[32,2798,164],{"class":49},[32,2800,2670],{"class":160},[32,2802,2769],{"class":49},[32,2804,59],{"class":45},[32,2806,239],{"class":49},[32,2808,792],{"class":108},[32,2810,201],{"class":49},[32,2812,812],{"class":108},[32,2814,201],{"class":49},[32,2816,1696],{"class":108},[32,2818,201],{"class":49},[32,2820,812],{"class":108},[32,2822,201],{"class":49},[32,2824,792],{"class":108},[32,2826,2790],{"class":49},[32,2828,2829],{"class":34,"line":355},[32,2830,139],{"class":49},[2381,2832,2833],{"v-slot:hints":27},[1355,2834,2835,2845,2852],{},[1358,2836,2837,2838,2841,2842],{},"Заведи ",[29,2839,2840],{},"seen := make(map[string]bool)"," или ",[29,2843,2844],{},"map[string]struct{}{}",[1358,2846,2847,2848,2851],{},"При каждом элементе проверяй ",[29,2849,2850],{},"if seen[item]"," — если true, это дубликат",[1358,2853,2854],{},"Верни первый найденный дубликат сразу (не жди конца слайса)",[14,2856],{},[1462,2858,2860],{"id":2859},"задачи-map","Задачи: Map",[14,2862],{},[11,2864,2865],{},[522,2866,2867],{},"Задача 1: Частотный анализ",[11,2869,2870,2873],{},[522,2871,2872],{},"Уровень:"," Лёгкая",[11,2875,2876,2879],{},[522,2877,2878],{},"Что проверяет:"," базовая работа с map, итерация",[11,2881,2882,2885,2886,2889],{},[522,2883,2884],{},"Условие:"," Напиши функцию ",[29,2887,2888],{},"wordCount(s string) map[string]int"," которая возвращает map где ключ — слово, значение — количество его вхождений в строку. Слова разделены пробелами, регистр не важен.",[11,2891,2892],{},[522,2893,2894],{},"Примеры:",[22,2896,2899],{"className":2897,"code":2898,"language":1387},[1385],"wordCount(\"the cat sat on the mat\")\n→ map[cat:1 mat:1 on:1 sat:1 the:2]\n\nwordCount(\"Go go GO\")\n→ map[go:3]\n",[29,2900,2898],{"__ignoreMap":27},[11,2902,2903],{},[522,2904,2905],{},"Решение:",[22,2907,2909],{"className":24,"code":2908,"language":26,"meta":27,"style":27},"package main\n\nimport (\n    \"fmt\"\n    \"strings\"\n)\n\nfunc wordCount(s string) map[string]int {\n    result := make(map[string]int)\n    words := strings.Fields(s) \u002F\u002F разбивает по пробелам, убирает лишние\n\n    for _, word := range words {\n        result[strings.ToLower(word)]++\n    }\n\n    return result\n}\n\nfunc main() {\n    fmt.Println(wordCount(\"the cat sat on the mat\"))\n    fmt.Println(wordCount(\"Go go GO\"))\n}\n",[29,2910,2911,2917,2921,2927,2935,2944,2948,2952,2980,3003,3022,3026,3040,3053,3057,3061,3068,3072,3076,3084,3103,3120],{"__ignoreMap":27},[32,2912,2913,2915],{"class":34,"line":35},[32,2914,843],{"class":45},[32,2916,846],{"class":160},[32,2918,2919],{"class":34,"line":42},[32,2920,72],{"emptyLinePlaceholder":71},[32,2922,2923,2925],{"class":34,"line":68},[32,2924,855],{"class":45},[32,2926,858],{"class":49},[32,2928,2929,2931,2933],{"class":34,"line":75},[32,2930,863],{"class":108},[32,2932,866],{"class":160},[32,2934,869],{"class":108},[32,2936,2937,2939,2942],{"class":34,"line":81},[32,2938,863],{"class":108},[32,2940,2941],{"class":160},"strings",[32,2943,869],{"class":108},[32,2945,2946],{"class":34,"line":105},[32,2947,177],{"class":49},[32,2949,2950],{"class":34,"line":122},[32,2951,72],{"emptyLinePlaceholder":71},[32,2953,2954,2956,2959,2961,2964,2966,2968,2970,2972,2974,2976,2978],{"class":34,"line":136},[32,2955,946],{"class":45},[32,2957,2958],{"class":160}," wordCount",[32,2960,164],{"class":49},[32,2962,2963],{"class":952},"s",[32,2965,972],{"class":45},[32,2967,207],{"class":49},[32,2969,53],{"class":45},[32,2971,56],{"class":49},[32,2973,59],{"class":45},[32,2975,62],{"class":49},[32,2977,99],{"class":45},[32,2979,905],{"class":49},[32,2981,2982,2985,2987,2989,2991,2993,2995,2997,2999,3001],{"class":34,"line":142},[32,2983,2984],{"class":49},"    result ",[32,2986,87],{"class":45},[32,2988,161],{"class":160},[32,2990,164],{"class":49},[32,2992,53],{"class":45},[32,2994,56],{"class":49},[32,2996,59],{"class":45},[32,2998,62],{"class":49},[32,3000,99],{"class":45},[32,3002,177],{"class":49},[32,3004,3005,3008,3010,3013,3016,3019],{"class":34,"line":147},[32,3006,3007],{"class":49},"    words ",[32,3009,87],{"class":45},[32,3011,3012],{"class":49}," strings.",[32,3014,3015],{"class":160},"Fields",[32,3017,3018],{"class":49},"(s) ",[32,3020,3021],{"class":38},"\u002F\u002F разбивает по пробелам, убирает лишние\n",[32,3023,3024],{"class":34,"line":153},[32,3025,72],{"emptyLinePlaceholder":71},[32,3027,3028,3030,3033,3035,3037],{"class":34,"line":180},[32,3029,2586],{"class":45},[32,3031,3032],{"class":49}," _, word ",[32,3034,87],{"class":45},[32,3036,501],{"class":45},[32,3038,3039],{"class":49}," words {\n",[32,3041,3042,3045,3048,3051],{"class":34,"line":355},[32,3043,3044],{"class":49},"        result[strings.",[32,3046,3047],{"class":160},"ToLower",[32,3049,3050],{"class":49},"(word)]",[32,3052,2604],{"class":45},[32,3054,3055],{"class":34,"line":360},[32,3056,1770],{"class":49},[32,3058,3059],{"class":34,"line":366},[32,3060,72],{"emptyLinePlaceholder":71},[32,3062,3063,3065],{"class":34,"line":385},[32,3064,1155],{"class":45},[32,3066,3067],{"class":49}," result\n",[32,3069,3070],{"class":34,"line":395},[32,3071,139],{"class":49},[32,3073,3074],{"class":34,"line":412},[32,3075,72],{"emptyLinePlaceholder":71},[32,3077,3078,3080,3082],{"class":34,"line":1022},[32,3079,946],{"class":45},[32,3081,1176],{"class":160},[32,3083,1179],{"class":49},[32,3085,3086,3088,3090,3092,3095,3097,3100],{"class":34,"line":1027},[32,3087,342],{"class":49},[32,3089,345],{"class":160},[32,3091,164],{"class":49},[32,3093,3094],{"class":160},"wordCount",[32,3096,164],{"class":49},[32,3098,3099],{"class":108},"\"the cat sat on the mat\"",[32,3101,3102],{"class":49},"))\n",[32,3104,3105,3107,3109,3111,3113,3115,3118],{"class":34,"line":1033},[32,3106,342],{"class":49},[32,3108,345],{"class":160},[32,3110,164],{"class":49},[32,3112,3094],{"class":160},[32,3114,164],{"class":49},[32,3116,3117],{"class":108},"\"Go go GO\"",[32,3119,3102],{"class":49},[32,3121,3122],{"class":34,"line":1045},[32,3123,139],{"class":49},[14,3125],{},[11,3127,3128],{},[522,3129,3130],{},"Задача 2: Группировка элементов",[11,3132,3133,3135],{},[522,3134,2872],{}," Средняя",[11,3137,3138,3140],{},[522,3139,2878],{}," map со слайсом как значением, проектирование структуры данных",[11,3142,3143,2885,3145,3148],{},[522,3144,2884],{},[29,3146,3147],{},"groupBy(words []string) map[int][]string"," которая группирует слова по длине. Слова в каждой группе должны быть в том же порядке что и в исходном слайсе.",[11,3150,3151],{},[522,3152,2894],{},[22,3154,3157],{"className":3155,"code":3156,"language":1387},[1385],"groupBy([]string{\"go\", \"is\", \"fun\", \"and\", \"fast\"})\n→ map[2:[go is] 3:[fun and] 4:[fast]]\n\ngroupBy([]string{\"a\", \"bb\", \"ccc\", \"dd\", \"e\"})\n→ map[1:[a e] 2:[bb dd] 3:[ccc]]\n",[29,3158,3156],{"__ignoreMap":27},[11,3160,3161],{},[522,3162,2905],{},[22,3164,3166],{"className":24,"code":3165,"language":26,"meta":27,"style":27},"package main\n\nimport \"fmt\"\n\nfunc groupBy(words []string) map[int][]string {\n    result := make(map[int][]string)\n\n    for _, word := range words {\n        length := len([]rune(word)) \u002F\u002F корректно для Unicode\n        result[length] = append(result[length], word)\n    }\n\n    return result\n}\n\nfunc main() {\n    fmt.Println(groupBy([]string{\"go\", \"is\", \"fun\", \"and\", \"fast\"}))\n    fmt.Println(groupBy([]string{\"a\", \"bb\", \"ccc\", \"dd\", \"e\"}))\n}\n\n\u002F\u002F append к nil-слайсу работает корректно —\n\u002F\u002F не нужно инициализировать result[length] отдельно.\n",[29,3167,3168,3174,3178,3188,3192,3223,3245,3249,3261,3282,3295,3299,3303,3309,3313,3317,3325,3367,3407,3411,3415,3420],{"__ignoreMap":27},[32,3169,3170,3172],{"class":34,"line":35},[32,3171,843],{"class":45},[32,3173,846],{"class":160},[32,3175,3176],{"class":34,"line":42},[32,3177,72],{"emptyLinePlaceholder":71},[32,3179,3180,3182,3184,3186],{"class":34,"line":68},[32,3181,855],{"class":45},[32,3183,2503],{"class":108},[32,3185,866],{"class":160},[32,3187,869],{"class":108},[32,3189,3190],{"class":34,"line":75},[32,3191,72],{"emptyLinePlaceholder":71},[32,3193,3194,3196,3199,3201,3204,3206,3208,3210,3212,3214,3216,3219,3221],{"class":34,"line":81},[32,3195,946],{"class":45},[32,3197,3198],{"class":160}," groupBy",[32,3200,164],{"class":49},[32,3202,3203],{"class":952},"words",[32,3205,2529],{"class":49},[32,3207,59],{"class":45},[32,3209,207],{"class":49},[32,3211,53],{"class":45},[32,3213,56],{"class":49},[32,3215,99],{"class":45},[32,3217,3218],{"class":49},"][]",[32,3220,59],{"class":45},[32,3222,905],{"class":49},[32,3224,3225,3227,3229,3231,3233,3235,3237,3239,3241,3243],{"class":34,"line":105},[32,3226,2984],{"class":49},[32,3228,87],{"class":45},[32,3230,161],{"class":160},[32,3232,164],{"class":49},[32,3234,53],{"class":45},[32,3236,56],{"class":49},[32,3238,99],{"class":45},[32,3240,3218],{"class":49},[32,3242,59],{"class":45},[32,3244,177],{"class":49},[32,3246,3247],{"class":34,"line":122},[32,3248,72],{"emptyLinePlaceholder":71},[32,3250,3251,3253,3255,3257,3259],{"class":34,"line":136},[32,3252,2586],{"class":45},[32,3254,3032],{"class":49},[32,3256,87],{"class":45},[32,3258,501],{"class":45},[32,3260,3039],{"class":49},[32,3262,3263,3266,3268,3271,3273,3276,3279],{"class":34,"line":142},[32,3264,3265],{"class":49},"        length ",[32,3267,87],{"class":45},[32,3269,3270],{"class":160}," len",[32,3272,2769],{"class":49},[32,3274,3275],{"class":45},"rune",[32,3277,3278],{"class":49},"(word)) ",[32,3280,3281],{"class":38},"\u002F\u002F корректно для Unicode\n",[32,3283,3284,3287,3289,3292],{"class":34,"line":147},[32,3285,3286],{"class":49},"        result[length] ",[32,3288,278],{"class":45},[32,3290,3291],{"class":160}," append",[32,3293,3294],{"class":49},"(result[length], word)\n",[32,3296,3297],{"class":34,"line":153},[32,3298,1770],{"class":49},[32,3300,3301],{"class":34,"line":180},[32,3302,72],{"emptyLinePlaceholder":71},[32,3304,3305,3307],{"class":34,"line":355},[32,3306,1155],{"class":45},[32,3308,3067],{"class":49},[32,3310,3311],{"class":34,"line":360},[32,3312,139],{"class":49},[32,3314,3315],{"class":34,"line":366},[32,3316,72],{"emptyLinePlaceholder":71},[32,3318,3319,3321,3323],{"class":34,"line":385},[32,3320,946],{"class":45},[32,3322,1176],{"class":160},[32,3324,1179],{"class":49},[32,3326,3327,3329,3331,3333,3336,3338,3340,3342,3345,3347,3350,3352,3355,3357,3360,3362,3365],{"class":34,"line":395},[32,3328,342],{"class":49},[32,3330,345],{"class":160},[32,3332,164],{"class":49},[32,3334,3335],{"class":160},"groupBy",[32,3337,2769],{"class":49},[32,3339,59],{"class":45},[32,3341,239],{"class":49},[32,3343,3344],{"class":108},"\"go\"",[32,3346,201],{"class":49},[32,3348,3349],{"class":108},"\"is\"",[32,3351,201],{"class":49},[32,3353,3354],{"class":108},"\"fun\"",[32,3356,201],{"class":49},[32,3358,3359],{"class":108},"\"and\"",[32,3361,201],{"class":49},[32,3363,3364],{"class":108},"\"fast\"",[32,3366,2790],{"class":49},[32,3368,3369,3371,3373,3375,3377,3379,3381,3383,3385,3387,3390,3392,3395,3397,3400,3402,3405],{"class":34,"line":412},[32,3370,342],{"class":49},[32,3372,345],{"class":160},[32,3374,164],{"class":49},[32,3376,3335],{"class":160},[32,3378,2769],{"class":49},[32,3380,59],{"class":45},[32,3382,239],{"class":49},[32,3384,792],{"class":108},[32,3386,201],{"class":49},[32,3388,3389],{"class":108},"\"bb\"",[32,3391,201],{"class":49},[32,3393,3394],{"class":108},"\"ccc\"",[32,3396,201],{"class":49},[32,3398,3399],{"class":108},"\"dd\"",[32,3401,201],{"class":49},[32,3403,3404],{"class":108},"\"e\"",[32,3406,2790],{"class":49},[32,3408,3409],{"class":34,"line":1022},[32,3410,139],{"class":49},[32,3412,3413],{"class":34,"line":1027},[32,3414,72],{"emptyLinePlaceholder":71},[32,3416,3417],{"class":34,"line":1033},[32,3418,3419],{"class":38},"\u002F\u002F append к nil-слайсу работает корректно —\n",[32,3421,3422],{"class":34,"line":1045},[32,3423,3424],{"class":38},"\u002F\u002F не нужно инициализировать result[length] отдельно.\n",[14,3426],{},[11,3428,3429],{},[522,3430,3431],{},"Задача 3: LRU-подобный кеш",[11,3433,3434,3436],{},[522,3435,2872],{}," Сложная",[11,3438,3439,3441],{},[522,3440,2878],{}," комбинирование map со структурами, проектирование API",[11,3443,3444,3446,3447,3450,3451,915],{},[522,3445,2884],{}," Реализуй простой кеш с ограничением размера. Когда кеш заполнен и добавляется новый элемент — удаляется самый старый. Реализуй методы ",[29,3448,3449],{},"Set(key string, value int)"," и ",[29,3452,3453],{},"Get(key string) (int, bool)",[11,3455,3456],{},[522,3457,2894],{},[22,3459,3462],{"className":3460,"code":3461,"language":1387},[1385],"cache := NewCache(3)\ncache.Set(\"a\", 1)\ncache.Set(\"b\", 2)\ncache.Set(\"c\", 3)\ncache.Get(\"a\")    → (1, true)\ncache.Set(\"d\", 4) \u002F\u002F кеш полон — удаляем \"b\" (самый старый)\ncache.Get(\"b\")    → (0, false)\ncache.Get(\"d\")    → (4, true)\n",[29,3463,3461],{"__ignoreMap":27},[11,3465,3466,3469],{},[522,3467,3468],{},"Подсказка:"," Храни порядок добавления через отдельный слайс ключей. При удалении убирай первый элемент слайса и соответствующий ключ из map.",[11,3471,3472],{},[522,3473,2905],{},[22,3475,3477],{"className":24,"code":3476,"language":26,"meta":27,"style":27},"package main\n\nimport \"fmt\"\n\ntype Cache struct {\n    capacity int\n    data     map[string]int\n    order    []string \u002F\u002F порядок добавления ключей\n}\n\nfunc NewCache(capacity int) *Cache {\n    return &Cache{\n        capacity: capacity,\n        data:     make(map[string]int),\n        order:    make([]string, 0, capacity),\n    }\n}\n\nfunc (c *Cache) Set(key string, value int) {\n    \u002F\u002F Если ключ уже есть — просто обновляем значение\n    if _, exists := c.data[key]; exists {\n        c.data[key] = value\n        return\n    }\n\n    \u002F\u002F Кеш полон — удаляем самый старый\n    if len(c.data) >= c.capacity {\n        oldest := c.order[0]\n        c.order = c.order[1:]\n        delete(c.data, oldest)\n    }\n\n    c.data[key] = value\n    c.order = append(c.order, key)\n}\n\nfunc (c *Cache) Get(key string) (int, bool) {\n    v, ok := c.data[key]\n    return v, ok\n}\n\nfunc main() {\n    cache := NewCache(3)\n    cache.Set(\"a\", 1)\n    cache.Set(\"b\", 2)\n    cache.Set(\"c\", 3)\n\n    fmt.Println(cache.Get(\"a\")) \u002F\u002F 1 true\n    cache.Set(\"d\", 4)\n    fmt.Println(cache.Get(\"b\")) \u002F\u002F 0 false — удалён\n    fmt.Println(cache.Get(\"d\")) \u002F\u002F 4 true\n}\n",[29,3478,3479,3485,3489,3499,3503,3514,3521,3536,3546,3550,3554,3577,3588,3593,3616,3634,3638,3642,3646,3679,3684,3696,3706,3711,3715,3719,3724,3739,3753,3767,3774,3778,3782,3791,3803,3807,3811,3843,3852,3858,3862,3866,3874,3889,3906,3922,3939,3944,3966,3984,4004,4024],{"__ignoreMap":27},[32,3480,3481,3483],{"class":34,"line":35},[32,3482,843],{"class":45},[32,3484,846],{"class":160},[32,3486,3487],{"class":34,"line":42},[32,3488,72],{"emptyLinePlaceholder":71},[32,3490,3491,3493,3495,3497],{"class":34,"line":68},[32,3492,855],{"class":45},[32,3494,2503],{"class":108},[32,3496,866],{"class":160},[32,3498,869],{"class":108},[32,3500,3501],{"class":34,"line":75},[32,3502,72],{"emptyLinePlaceholder":71},[32,3504,3505,3507,3510,3512],{"class":34,"line":81},[32,3506,896],{"class":45},[32,3508,3509],{"class":160}," Cache",[32,3511,902],{"class":45},[32,3513,905],{"class":49},[32,3515,3516,3519],{"class":34,"line":105},[32,3517,3518],{"class":49},"    capacity ",[32,3520,65],{"class":45},[32,3522,3523,3526,3528,3530,3532,3534],{"class":34,"line":122},[32,3524,3525],{"class":49},"    data     ",[32,3527,53],{"class":45},[32,3529,56],{"class":49},[32,3531,59],{"class":45},[32,3533,62],{"class":49},[32,3535,65],{"class":45},[32,3537,3538,3541,3543],{"class":34,"line":136},[32,3539,3540],{"class":49},"    order    []",[32,3542,59],{"class":45},[32,3544,3545],{"class":38}," \u002F\u002F порядок добавления ключей\n",[32,3547,3548],{"class":34,"line":142},[32,3549,139],{"class":49},[32,3551,3552],{"class":34,"line":147},[32,3553,72],{"emptyLinePlaceholder":71},[32,3555,3556,3558,3561,3563,3566,3568,3570,3572,3575],{"class":34,"line":153},[32,3557,946],{"class":45},[32,3559,3560],{"class":160}," NewCache",[32,3562,164],{"class":49},[32,3564,3565],{"class":952},"capacity",[32,3567,621],{"class":45},[32,3569,207],{"class":49},[32,3571,956],{"class":45},[32,3573,3574],{"class":160},"Cache",[32,3576,905],{"class":49},[32,3578,3579,3581,3584,3586],{"class":34,"line":180},[32,3580,1155],{"class":45},[32,3582,3583],{"class":45}," &",[32,3585,3574],{"class":160},[32,3587,102],{"class":49},[32,3589,3590],{"class":34,"line":355},[32,3591,3592],{"class":49},"        capacity: capacity,\n",[32,3594,3595,3598,3601,3603,3605,3607,3609,3611,3613],{"class":34,"line":360},[32,3596,3597],{"class":49},"        data:     ",[32,3599,3600],{"class":160},"make",[32,3602,164],{"class":49},[32,3604,53],{"class":45},[32,3606,56],{"class":49},[32,3608,59],{"class":45},[32,3610,62],{"class":49},[32,3612,99],{"class":45},[32,3614,3615],{"class":49},"),\n",[32,3617,3618,3621,3623,3625,3627,3629,3631],{"class":34,"line":366},[32,3619,3620],{"class":49},"        order:    ",[32,3622,3600],{"class":160},[32,3624,2769],{"class":49},[32,3626,59],{"class":45},[32,3628,201],{"class":49},[32,3630,1451],{"class":115},[32,3632,3633],{"class":49},", capacity),\n",[32,3635,3636],{"class":34,"line":385},[32,3637,1770],{"class":49},[32,3639,3640],{"class":34,"line":395},[32,3641,139],{"class":49},[32,3643,3644],{"class":34,"line":412},[32,3645,72],{"emptyLinePlaceholder":71},[32,3647,3648,3650,3652,3655,3657,3659,3661,3663,3665,3668,3670,3672,3675,3677],{"class":34,"line":1022},[32,3649,946],{"class":45},[32,3651,949],{"class":49},[32,3653,3654],{"class":952},"c ",[32,3656,956],{"class":45},[32,3658,3574],{"class":160},[32,3660,207],{"class":49},[32,3662,964],{"class":160},[32,3664,164],{"class":49},[32,3666,3667],{"class":952},"key",[32,3669,972],{"class":45},[32,3671,201],{"class":49},[32,3673,3674],{"class":952},"value",[32,3676,621],{"class":45},[32,3678,982],{"class":49},[32,3680,3681],{"class":34,"line":1027},[32,3682,3683],{"class":38},"    \u002F\u002F Если ключ уже есть — просто обновляем значение\n",[32,3685,3686,3688,3691,3693],{"class":34,"line":1033},[32,3687,1724],{"class":45},[32,3689,3690],{"class":49}," _, exists ",[32,3692,87],{"class":45},[32,3694,3695],{"class":49}," c.data[key]; exists {\n",[32,3697,3698,3701,3703],{"class":34,"line":1045},[32,3699,3700],{"class":49},"        c.data[key] ",[32,3702,278],{"class":45},[32,3704,3705],{"class":49}," value\n",[32,3707,3708],{"class":34,"line":1057},[32,3709,3710],{"class":45},"        return\n",[32,3712,3713],{"class":34,"line":1072},[32,3714,1770],{"class":49},[32,3716,3717],{"class":34,"line":1077},[32,3718,72],{"emptyLinePlaceholder":71},[32,3720,3721],{"class":34,"line":1082},[32,3722,3723],{"class":38},"    \u002F\u002F Кеш полон — удаляем самый старый\n",[32,3725,3726,3728,3730,3733,3736],{"class":34,"line":1119},[32,3727,1724],{"class":45},[32,3729,3270],{"class":160},[32,3731,3732],{"class":49},"(c.data) ",[32,3734,3735],{"class":45},">=",[32,3737,3738],{"class":49}," c.capacity {\n",[32,3740,3741,3744,3746,3749,3751],{"class":34,"line":1129},[32,3742,3743],{"class":49},"        oldest ",[32,3745,87],{"class":45},[32,3747,3748],{"class":49}," c.order[",[32,3750,1451],{"class":115},[32,3752,329],{"class":49},[32,3754,3755,3758,3760,3762,3764],{"class":34,"line":1141},[32,3756,3757],{"class":49},"        c.order ",[32,3759,278],{"class":45},[32,3761,3748],{"class":49},[32,3763,701],{"class":115},[32,3765,3766],{"class":49},":]\n",[32,3768,3769,3771],{"class":34,"line":1152},[32,3770,1738],{"class":160},[32,3772,3773],{"class":49},"(c.data, oldest)\n",[32,3775,3776],{"class":34,"line":1161},[32,3777,1770],{"class":49},[32,3779,3780],{"class":34,"line":1166},[32,3781,72],{"emptyLinePlaceholder":71},[32,3783,3784,3787,3789],{"class":34,"line":1171},[32,3785,3786],{"class":49},"    c.data[key] ",[32,3788,278],{"class":45},[32,3790,3705],{"class":49},[32,3792,3793,3796,3798,3800],{"class":34,"line":1182},[32,3794,3795],{"class":49},"    c.order ",[32,3797,278],{"class":45},[32,3799,3291],{"class":160},[32,3801,3802],{"class":49},"(c.order, key)\n",[32,3804,3805],{"class":34,"line":1188},[32,3806,139],{"class":49},[32,3808,3809],{"class":34,"line":1194},[32,3810,72],{"emptyLinePlaceholder":71},[32,3812,3813,3815,3817,3819,3821,3823,3825,3827,3829,3831,3833,3835,3837,3839,3841],{"class":34,"line":1210},[32,3814,946],{"class":45},[32,3816,949],{"class":49},[32,3818,3654],{"class":952},[32,3820,956],{"class":45},[32,3822,3574],{"class":160},[32,3824,207],{"class":49},[32,3826,1098],{"class":160},[32,3828,164],{"class":49},[32,3830,3667],{"class":952},[32,3832,972],{"class":45},[32,3834,1107],{"class":49},[32,3836,99],{"class":45},[32,3838,201],{"class":49},[32,3840,1114],{"class":45},[32,3842,982],{"class":49},[32,3844,3845,3847,3849],{"class":34,"line":1229},[32,3846,1144],{"class":49},[32,3848,87],{"class":45},[32,3850,3851],{"class":49}," c.data[key]\n",[32,3853,3854,3856],{"class":34,"line":1248},[32,3855,1155],{"class":45},[32,3857,1158],{"class":49},[32,3859,3860],{"class":34,"line":1258},[32,3861,139],{"class":49},[32,3863,3864],{"class":34,"line":1272},[32,3865,72],{"emptyLinePlaceholder":71},[32,3867,3868,3870,3872],{"class":34,"line":1302},[32,3869,946],{"class":45},[32,3871,1176],{"class":160},[32,3873,1179],{"class":49},[32,3875,3876,3879,3881,3883,3885,3887],{"class":34,"line":1312},[32,3877,3878],{"class":49},"    cache ",[32,3880,87],{"class":45},[32,3882,3560],{"class":160},[32,3884,164],{"class":49},[32,3886,587],{"class":115},[32,3888,177],{"class":49},[32,3890,3891,3894,3896,3898,3900,3902,3904],{"class":34,"line":1324},[32,3892,3893],{"class":49},"    cache.",[32,3895,964],{"class":160},[32,3897,164],{"class":49},[32,3899,792],{"class":108},[32,3901,201],{"class":49},[32,3903,701],{"class":115},[32,3905,177],{"class":49},[32,3907,3908,3910,3912,3914,3916,3918,3920],{"class":34,"line":1330},[32,3909,3893],{"class":49},[32,3911,964],{"class":160},[32,3913,164],{"class":49},[32,3915,812],{"class":108},[32,3917,201],{"class":49},[32,3919,1691],{"class":115},[32,3921,177],{"class":49},[32,3923,3925,3927,3929,3931,3933,3935,3937],{"class":34,"line":3924},46,[32,3926,3893],{"class":49},[32,3928,964],{"class":160},[32,3930,164],{"class":49},[32,3932,1696],{"class":108},[32,3934,201],{"class":49},[32,3936,587],{"class":115},[32,3938,177],{"class":49},[32,3940,3942],{"class":34,"line":3941},47,[32,3943,72],{"emptyLinePlaceholder":71},[32,3945,3947,3949,3951,3954,3956,3958,3960,3963],{"class":34,"line":3946},48,[32,3948,342],{"class":49},[32,3950,345],{"class":160},[32,3952,3953],{"class":49},"(cache.",[32,3955,1098],{"class":160},[32,3957,164],{"class":49},[32,3959,792],{"class":108},[32,3961,3962],{"class":49},")) ",[32,3964,3965],{"class":38},"\u002F\u002F 1 true\n",[32,3967,3969,3971,3973,3975,3977,3979,3982],{"class":34,"line":3968},49,[32,3970,3893],{"class":49},[32,3972,964],{"class":160},[32,3974,164],{"class":49},[32,3976,1755],{"class":108},[32,3978,201],{"class":49},[32,3980,3981],{"class":115},"4",[32,3983,177],{"class":49},[32,3985,3987,3989,3991,3993,3995,3997,3999,4001],{"class":34,"line":3986},50,[32,3988,342],{"class":49},[32,3990,345],{"class":160},[32,3992,3953],{"class":49},[32,3994,1098],{"class":160},[32,3996,164],{"class":49},[32,3998,812],{"class":108},[32,4000,3962],{"class":49},[32,4002,4003],{"class":38},"\u002F\u002F 0 false — удалён\n",[32,4005,4007,4009,4011,4013,4015,4017,4019,4021],{"class":34,"line":4006},51,[32,4008,342],{"class":49},[32,4010,345],{"class":160},[32,4012,3953],{"class":49},[32,4014,1098],{"class":160},[32,4016,164],{"class":49},[32,4018,1755],{"class":108},[32,4020,3962],{"class":49},[32,4022,4023],{"class":38},"\u002F\u002F 4 true\n",[32,4025,4027],{"class":34,"line":4026},52,[32,4028,139],{"class":49},[4030,4031,4032],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}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 pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":27,"searchDepth":42,"depth":42,"links":4034},[4035,4039,4040,4041,4042,4048,4053,4054,4055],{"id":19,"depth":42,"text":20,"children":4036},[4037,4038],{"id":214,"depth":68,"text":215},{"id":423,"depth":68,"text":424},{"id":530,"depth":42,"text":531},{"id":738,"depth":42,"text":739},{"id":1343,"depth":42,"text":1344},{"id":1406,"depth":42,"text":1407,"children":4043},[4044,4045,4046,4047],{"id":1417,"depth":68,"text":1418},{"id":1471,"depth":68,"text":1472},{"id":1516,"depth":68,"text":1517},{"id":1538,"depth":68,"text":1539},{"id":1642,"depth":42,"text":1643,"children":4049},[4050,4051,4052],{"id":1646,"depth":68,"text":1647},{"id":1780,"depth":68,"text":1781},{"id":1836,"depth":68,"text":1837},{"id":1957,"depth":42,"text":1958},{"id":2168,"depth":42,"text":2169},{"id":2310,"depth":42,"text":2311},1781458319603]