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