[{"data":1,"prerenderedAt":3350},["ShallowReactive",2],{"content:\u002F04-advanced\u002F02-unsafe":3},{"title":4,"description":5,"path":6,"body":7},"Пакет unsafe","Обход системы типов Go — конвертация между указателями разных типов и арифметика указателей.","\u002F04-advanced\u002F02-unsafe",{"type":8,"value":9,"toc":3314},"minimark",[10,13,143,155,160,165,170,180,192,258,262,270,375,378,381,385,388,448,452,520,528,532,542,633,640,671,675,682,717,721,727,763,769,784,796,800,808,810,813,817,825,833,841,848,850,853,857,864,871,1059,1069,1072,1075,1082,1088,1230,1233,1259,1262,1410,1413,1417,1423,1427,1430,1433,1453,1456,1468,1471,1475,1491,1494,1537,1541,1554,1630,1633,1657,1660,1808,1814,1818,1821,1825,1830,1833,1856,1863,1867,1870,1953,1959,1997,2008,2093,2101,2105,2114,2117,2215,2222,2226,2229,2235,2428,2431,2447,2451,2611,2613,2646,2650,2745,2747,2767,2771,2777,2855,2857,2861,2914,3049,3310],[11,12,5],"p",{},[14,15,16,42],"table",{},[17,18,19],"thead",{},[20,21,22,26,32,37],"tr",{},[23,24],"th",{"align":25},"left",[23,27,28],{"align":25},[29,30,31],"code",{},"*T",[23,33,34],{"align":25},[29,35,36],{},"unsafe.Pointer",[23,38,39],{"align":25},[29,40,41],{},"uintptr",[43,44,45,60,83,102,114,127],"tbody",{},[20,46,47,51,54,57],{},[48,49,50],"td",{"align":25},"Что это",[48,52,53],{"align":25},"Типизированный указатель",[48,55,56],{"align":25},"Нетипизированный указатель (void* в C)",[48,58,59],{"align":25},"Целое число (адрес как integer)",[20,61,62,65,75,80],{},[48,63,64],{"align":25},"Типизация",[48,66,67,68,71,72],{"align":25},"Строгая: ",[29,69,70],{},"*int"," нельзя кастить в ",[29,73,74],{},"*float64",[48,76,77,78],{"align":25},"Нет типа: можно кастить в любой ",[29,79,31],{},[48,81,82],{"align":25},"Не указатель вообще",[20,84,85,88,94,99],{},[48,86,87],{"align":25},"Разыменование",[48,89,90,93],{"align":25},[29,91,92],{},"*p"," — да",[48,95,96,97],{"align":25},"Нельзя напрямую, сначала каст в ",[29,98,31],{},[48,100,101],{"align":25},"Нельзя",[20,103,104,107,109,111],{},[48,105,106],{"align":25},"Арифметика",[48,108,101],{"align":25},[48,110,101],{"align":25},[48,112,113],{"align":25},"Можно (+, -)",[20,115,116,119,122,124],{},[48,117,118],{"align":25},"Удерживает объект живым",[48,120,121],{"align":25},"Да",[48,123,121],{"align":25},[48,125,126],{"align":25},"Нет — для GC это просто число",[20,128,129,132,135,140],{},[48,130,131],{"align":25},"Можно вернуть обратно в указатель",[48,133,134],{"align":25},"Уже указатель",[48,136,137,138],{"align":25},"Да, через ",[29,139,31],{},[48,141,142],{"align":25},"Только в строго описанных паттернах",[11,144,145,147,148,151,152,154],{},[29,146,36],{}," — нетипизированный указатель, аналог ",[29,149,150],{},"void*"," в C. Позволяет кастить между любыми ",[29,153,31],{},".",[11,156,157,159],{},[29,158,41],{}," — обычное целое число, хранящее адрес. GC не считает его указателем и не использует как причину держать объект живым.",[161,162,164],"h2",{"id":163},"правила-unsafe","Правила unsafe",[166,167,169],"h3",{"id":168},"цепочка-конверсий","Цепочка конверсий",[171,172,177],"pre",{"className":173,"code":175,"language":176},[174],"language-text","*T  ↔  unsafe.Pointer  ↔  *U       \u002F\u002F каст между типами\n*T  ↔  unsafe.Pointer  ↔  uintptr  \u002F\u002F арифметика указателей\n","text",[29,178,175],{"__ignoreMap":179},"",[11,181,182,183,185,186,188,189,191],{},"Напрямую ",[29,184,70],{}," → ",[29,187,74],{}," — compile error. Через ",[29,190,36],{}," — можно:",[171,193,197],{"className":194,"code":195,"language":196,"meta":179,"style":179},"language-go shiki shiki-themes github-dark","var i int64 = 42\nf := *(*float64)(unsafe.Pointer(&i)) \u002F\u002F реинтерпретация тех же битов как float64\n","go",[29,198,199,222],{"__ignoreMap":179},[200,201,204,208,212,215,218],"span",{"class":202,"line":203},"line",1,[200,205,207],{"class":206},"snl16","var",[200,209,211],{"class":210},"s95oV"," i ",[200,213,214],{"class":206},"int64",[200,216,217],{"class":206}," =",[200,219,221],{"class":220},"sDLfK"," 42\n",[200,223,225,228,231,234,237,239,242,246,248,251,254],{"class":202,"line":224},2,[200,226,227],{"class":210},"f ",[200,229,230],{"class":206},":=",[200,232,233],{"class":206}," *",[200,235,236],{"class":210},"(",[200,238,74],{"class":206},[200,240,241],{"class":210},")(unsafe.",[200,243,245],{"class":244},"svObZ","Pointer",[200,247,236],{"class":210},[200,249,250],{"class":206},"&",[200,252,253],{"class":210},"i)) ",[200,255,257],{"class":256},"sAwPA","\u002F\u002F реинтерпретация тех же битов как float64\n",[166,259,261],{"id":260},"почему-uintptr-опасен","Почему uintptr опасен",[11,263,264,266,267,269],{},[29,265,41],{}," не является указателем. Если адрес сохранён в ",[29,268,41],{},", объект больше не удерживается этим значением, а компилятор и GC не обязаны сохранять связь между числом и исходным объектом.",[171,271,273],{"className":194,"code":272,"language":196,"meta":179,"style":179},"\u002F\u002F ❌ между строками объект не удерживается через addr\naddr := uintptr(unsafe.Pointer(&x))  \u002F\u002F сохранили число\n\u002F\u002F ... код, вызовы функций, GC, оптимизации компилятора ...\np := unsafe.Pointer(addr)            \u002F\u002F dangling pointer\n\n\u002F\u002F ✅ одно выражение — допустимый паттерн unsafe.Pointer\np := unsafe.Pointer(uintptr(unsafe.Pointer(&x)) + offset)\n",[29,274,275,280,305,311,330,337,343],{"__ignoreMap":179},[200,276,277],{"class":202,"line":203},[200,278,279],{"class":256},"\u002F\u002F ❌ между строками объект не удерживается через addr\n",[200,281,282,285,287,290,293,295,297,299,302],{"class":202,"line":224},[200,283,284],{"class":210},"addr ",[200,286,230],{"class":206},[200,288,289],{"class":206}," uintptr",[200,291,292],{"class":210},"(unsafe.",[200,294,245],{"class":244},[200,296,236],{"class":210},[200,298,250],{"class":206},[200,300,301],{"class":210},"x))  ",[200,303,304],{"class":256},"\u002F\u002F сохранили число\n",[200,306,308],{"class":202,"line":307},3,[200,309,310],{"class":256},"\u002F\u002F ... код, вызовы функций, GC, оптимизации компилятора ...\n",[200,312,314,317,319,322,324,327],{"class":202,"line":313},4,[200,315,316],{"class":210},"p ",[200,318,230],{"class":206},[200,320,321],{"class":210}," unsafe.",[200,323,245],{"class":244},[200,325,326],{"class":210},"(addr)            ",[200,328,329],{"class":256},"\u002F\u002F dangling pointer\n",[200,331,333],{"class":202,"line":332},5,[200,334,336],{"emptyLinePlaceholder":335},true,"\n",[200,338,340],{"class":202,"line":339},6,[200,341,342],{"class":256},"\u002F\u002F ✅ одно выражение — допустимый паттерн unsafe.Pointer\n",[200,344,346,348,350,352,354,356,358,360,362,364,366,369,372],{"class":202,"line":345},7,[200,347,316],{"class":210},[200,349,230],{"class":206},[200,351,321],{"class":210},[200,353,245],{"class":244},[200,355,236],{"class":210},[200,357,41],{"class":206},[200,359,292],{"class":210},[200,361,245],{"class":244},[200,363,236],{"class":210},[200,365,250],{"class":206},[200,367,368],{"class":210},"x)) ",[200,370,371],{"class":206},"+",[200,373,374],{"class":210}," offset)\n",[376,377],"hr",{},[11,379,380],{},"6 легальных паттернов из документации. Всё остальное — undefined behavior.",[166,382,384],{"id":383},"_1-каст-t-unsafepointer-u","1. Каст *T → unsafe.Pointer → *U",[11,386,387],{},"Реинтерпретация памяти. Оба типа должны иметь совместимый memory layout.",[171,389,391],{"className":194,"code":390,"language":196,"meta":179,"style":179},"p := Point2D{X: 100, Y: 200}\nv := *(*Vec2)(unsafe.Pointer(&p))  \u002F\u002F ок если layout одинаковый\n",[29,392,393,417],{"__ignoreMap":179},[200,394,395,397,399,402,405,408,411,414],{"class":202,"line":203},[200,396,316],{"class":210},[200,398,230],{"class":206},[200,400,401],{"class":244}," Point2D",[200,403,404],{"class":210},"{X: ",[200,406,407],{"class":220},"100",[200,409,410],{"class":210},", Y: ",[200,412,413],{"class":220},"200",[200,415,416],{"class":210},"}\n",[200,418,419,422,424,426,428,431,434,436,438,440,442,445],{"class":202,"line":224},[200,420,421],{"class":210},"v ",[200,423,230],{"class":206},[200,425,233],{"class":206},[200,427,236],{"class":210},[200,429,430],{"class":206},"*",[200,432,433],{"class":244},"Vec2",[200,435,241],{"class":210},[200,437,245],{"class":244},[200,439,236],{"class":210},[200,441,250],{"class":206},[200,443,444],{"class":210},"p))  ",[200,446,447],{"class":256},"\u002F\u002F ок если layout одинаковый\n",[166,449,451],{"id":450},"_2-pointer-uintptr-только-для-печати","2. Pointer → uintptr (только для печати)",[171,453,455],{"className":194,"code":454,"language":196,"meta":179,"style":179},"import \"unsafe\"\n\nx := 42\nfmt.Printf(\"addr: %x\\n\", uintptr(unsafe.Pointer(&x)))\n",[29,456,457,472,476,485],{"__ignoreMap":179},[200,458,459,462,466,469],{"class":202,"line":203},[200,460,461],{"class":206},"import",[200,463,465],{"class":464},"sU2Wk"," \"",[200,467,468],{"class":244},"unsafe",[200,470,471],{"class":464},"\"\n",[200,473,474],{"class":202,"line":224},[200,475,336],{"emptyLinePlaceholder":335},[200,477,478,481,483],{"class":202,"line":307},[200,479,480],{"class":210},"x ",[200,482,230],{"class":206},[200,484,221],{"class":220},[200,486,487,490,493,495,498,501,504,507,509,511,513,515,517],{"class":202,"line":313},[200,488,489],{"class":210},"fmt.",[200,491,492],{"class":244},"Printf",[200,494,236],{"class":210},[200,496,497],{"class":464},"\"addr: ",[200,499,500],{"class":220},"%x\\n",[200,502,503],{"class":464},"\"",[200,505,506],{"class":210},", ",[200,508,41],{"class":206},[200,510,292],{"class":210},[200,512,245],{"class":244},[200,514,236],{"class":210},[200,516,250],{"class":206},[200,518,519],{"class":210},"x)))\n",[11,521,522,523,527],{},"Pointer → uintptr для печати — допустимо. Обратно uintptr → Pointer конвертировать ",[524,525,526],"strong",{},"нельзя"," (кроме паттернов 3-5).",[166,529,531],{"id":530},"_3-арифметика-в-одном-выражении","3. Арифметика — в одном выражении",[11,533,534,535,538,539,541],{},"Конверсия uintptr → Pointer ",[524,536,537],{},"обязана"," быть в одном выражении — иначе ",[29,540,41],{}," теряет связь с объектом.",[171,543,545],{"className":194,"code":544,"language":196,"meta":179,"style":179},"\u002F\u002F ✅ одно выражение\np := unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.age))\n\n\u002F\u002F ❌ сохранил в переменную — dangling\nu := uintptr(unsafe.Pointer(&s))\np := unsafe.Pointer(u + offset)\n",[29,546,547,552,587,591,596,616],{"__ignoreMap":179},[200,548,549],{"class":202,"line":203},[200,550,551],{"class":256},"\u002F\u002F ✅ одно выражение\n",[200,553,554,556,558,560,562,564,566,568,570,572,574,577,579,581,584],{"class":202,"line":224},[200,555,316],{"class":210},[200,557,230],{"class":206},[200,559,321],{"class":210},[200,561,245],{"class":244},[200,563,236],{"class":210},[200,565,41],{"class":206},[200,567,292],{"class":210},[200,569,245],{"class":244},[200,571,236],{"class":210},[200,573,250],{"class":206},[200,575,576],{"class":210},"s)) ",[200,578,371],{"class":206},[200,580,321],{"class":210},[200,582,583],{"class":244},"Offsetof",[200,585,586],{"class":210},"(s.age))\n",[200,588,589],{"class":202,"line":307},[200,590,336],{"emptyLinePlaceholder":335},[200,592,593],{"class":202,"line":313},[200,594,595],{"class":256},"\u002F\u002F ❌ сохранил в переменную — dangling\n",[200,597,598,601,603,605,607,609,611,613],{"class":202,"line":332},[200,599,600],{"class":210},"u ",[200,602,230],{"class":206},[200,604,289],{"class":206},[200,606,292],{"class":210},[200,608,245],{"class":244},[200,610,236],{"class":210},[200,612,250],{"class":206},[200,614,615],{"class":210},"s))\n",[200,617,618,620,622,624,626,629,631],{"class":202,"line":339},[200,619,316],{"class":210},[200,621,230],{"class":206},[200,623,321],{"class":210},[200,625,245],{"class":244},[200,627,628],{"class":210},"(u ",[200,630,371],{"class":206},[200,632,374],{"class":210},[11,634,635,636,639],{},"С Go 1.17 есть ",[29,637,638],{},"unsafe.Add"," — делает то же самое безопаснее:",[171,641,643],{"className":194,"code":642,"language":196,"meta":179,"style":179},"p := unsafe.Add(unsafe.Pointer(&s), unsafe.Offsetof(s.age))\n",[29,644,645],{"__ignoreMap":179},[200,646,647,649,651,653,656,658,660,662,664,667,669],{"class":202,"line":203},[200,648,316],{"class":210},[200,650,230],{"class":206},[200,652,321],{"class":210},[200,654,655],{"class":244},"Add",[200,657,292],{"class":210},[200,659,245],{"class":244},[200,661,236],{"class":210},[200,663,250],{"class":206},[200,665,666],{"class":210},"s), unsafe.",[200,668,583],{"class":244},[200,670,586],{"class":210},[166,672,674],{"id":673},"_4-syscall-аргументы","4. Syscall аргументы",[11,676,677,678,681],{},"Конверсия в uintptr допустима ",[524,679,680],{},"только прямо в аргументе"," вызова. Компилятор специально удерживает объект от GC до конца вызова.",[171,683,685],{"className":194,"code":684,"language":196,"meta":179,"style":179},"syscall.Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(n))\n",[29,686,687],{"__ignoreMap":179},[200,688,689,692,695,698,700,703,705,707,709,712,714],{"class":202,"line":203},[200,690,691],{"class":210},"syscall.",[200,693,694],{"class":244},"Syscall",[200,696,697],{"class":210},"(SYS_READ, ",[200,699,41],{"class":206},[200,701,702],{"class":210},"(fd), ",[200,704,41],{"class":206},[200,706,292],{"class":210},[200,708,245],{"class":244},[200,710,711],{"class":210},"(p)), ",[200,713,41],{"class":206},[200,715,716],{"class":210},"(n))\n",[166,718,720],{"id":719},"_5-6-reflectvalue-и-sliceheaderstringheader","5-6. reflect.Value и SliceHeader\u002FStringHeader",[11,722,723,726],{},[29,724,725],{},"reflect.Value.Pointer()"," возвращает uintptr — конвертировать обратно можно только сразу:",[171,728,730],{"className":194,"code":729,"language":196,"meta":179,"style":179},"p := unsafe.Pointer(reflect.ValueOf(&x).Pointer()) \u002F\u002F сразу в одном выражении\n",[29,731,732],{"__ignoreMap":179},[200,733,734,736,738,740,742,745,748,750,752,755,757,760],{"class":202,"line":203},[200,735,316],{"class":210},[200,737,230],{"class":206},[200,739,321],{"class":210},[200,741,245],{"class":244},[200,743,744],{"class":210},"(reflect.",[200,746,747],{"class":244},"ValueOf",[200,749,236],{"class":210},[200,751,250],{"class":206},[200,753,754],{"class":210},"x).",[200,756,245],{"class":244},[200,758,759],{"class":210},"()) ",[200,761,762],{"class":256},"\u002F\u002F сразу в одном выражении\n",[11,764,765,768],{},[29,766,767],{},"SliceHeader\u002FStringHeader"," — deprecated с Go 1.20.",[11,770,771,772,506,775,506,778,506,781,154],{},"Вместо них: ",[29,773,774],{},"unsafe.String",[29,776,777],{},"unsafe.StringData",[29,779,780],{},"unsafe.Slice",[29,782,783],{},"unsafe.SliceData",[11,785,786,787,789,790,792,793,795],{},"Почему это важно: ",[29,788,725],{}," тоже возвращает ",[29,791,41],{},". Это удобно для логирования адресов, но опасно для обратного превращения в указатель. Если нужен живой указатель, ищи API, который возвращает ",[29,794,36],{},", или держи исходный объект обычной Go-ссылкой до конца работы.",[166,797,799],{"id":798},"go-vet","go vet",[11,801,802,804,805,807],{},[29,803,799],{}," проверяет паттерны unsafe.Pointer и ловит нарушения правил. Если ",[29,806,799],{}," ругается — код невалиден.",[376,809],{},[11,811,812],{},"Три compile-time функции для получения информации о layout типов в памяти.",[166,814,816],{"id":815},"функции","Функции",[11,818,819,824],{},[524,820,821],{},[29,822,823],{},"unsafe.Sizeof(x)"," — размер типа в байтах. Не учитывает данные за указателем: для слайса вернёт 24 (размер заголовка), а не размер underlying array.",[11,826,827,832],{},[524,828,829],{},[29,830,831],{},"unsafe.Alignof(x)"," — выравнивание типа в байтах. CPU читает память блоками, адрес поля должен быть кратен этому числу.",[11,834,835,840],{},[524,836,837],{},[29,838,839],{},"unsafe.Offsetof(s.field)"," — смещение поля от начала структуры в байтах. Работает только для полей структур.",[11,842,843,844,847],{},"Все три функции вычисляются в ",[524,845,846],{},"compile-time"," — это не runtime-вызовы.",[376,849],{},[11,851,852],{},"Когда unsafe реально используется и когда не стоит.",[161,854,856],{"id":855},"практические-кейсы","Практические кейсы",[166,858,860,861,863],{"id":859},"zero-copy-string-byte","Zero-copy string ↔ ",[200,862],{},"byte",[11,865,866,867,870],{},"Обычная конверсия ",[29,868,869],{},"[]byte(s)"," копирует данные. unsafe — нет:",[171,872,874],{"className":194,"code":873,"language":196,"meta":179,"style":179},"\u002F\u002F Go 1.20+\nfunc StringToBytes(s string) []byte {\n    if len(s) == 0 {\n        return nil\n    }\n    return unsafe.Slice(unsafe.StringData(s), len(s))\n}\n\nfunc BytesToString(b []byte) string {\n    if len(b) == 0 {\n        return \"\"\n    }\n    return unsafe.String(&b[0], len(b))\n}\n",[29,875,876,881,906,925,933,938,962,966,971,997,1013,1021,1026,1054],{"__ignoreMap":179},[200,877,878],{"class":202,"line":203},[200,879,880],{"class":256},"\u002F\u002F Go 1.20+\n",[200,882,883,886,889,891,895,898,901,903],{"class":202,"line":224},[200,884,885],{"class":206},"func",[200,887,888],{"class":244}," StringToBytes",[200,890,236],{"class":210},[200,892,894],{"class":893},"s9osk","s",[200,896,897],{"class":206}," string",[200,899,900],{"class":210},") []",[200,902,863],{"class":206},[200,904,905],{"class":210}," {\n",[200,907,908,911,914,917,920,923],{"class":202,"line":307},[200,909,910],{"class":206},"    if",[200,912,913],{"class":244}," len",[200,915,916],{"class":210},"(s) ",[200,918,919],{"class":206},"==",[200,921,922],{"class":220}," 0",[200,924,905],{"class":210},[200,926,927,930],{"class":202,"line":313},[200,928,929],{"class":206},"        return",[200,931,932],{"class":220}," nil\n",[200,934,935],{"class":202,"line":332},[200,936,937],{"class":210},"    }\n",[200,939,940,943,945,948,950,953,956,959],{"class":202,"line":339},[200,941,942],{"class":206},"    return",[200,944,321],{"class":210},[200,946,947],{"class":244},"Slice",[200,949,292],{"class":210},[200,951,952],{"class":244},"StringData",[200,954,955],{"class":210},"(s), ",[200,957,958],{"class":244},"len",[200,960,961],{"class":210},"(s))\n",[200,963,964],{"class":202,"line":345},[200,965,416],{"class":210},[200,967,969],{"class":202,"line":968},8,[200,970,336],{"emptyLinePlaceholder":335},[200,972,974,976,979,981,984,987,989,992,995],{"class":202,"line":973},9,[200,975,885],{"class":206},[200,977,978],{"class":244}," BytesToString",[200,980,236],{"class":210},[200,982,983],{"class":893},"b",[200,985,986],{"class":210}," []",[200,988,863],{"class":206},[200,990,991],{"class":210},") ",[200,993,994],{"class":206},"string",[200,996,905],{"class":210},[200,998,1000,1002,1004,1007,1009,1011],{"class":202,"line":999},10,[200,1001,910],{"class":206},[200,1003,913],{"class":244},[200,1005,1006],{"class":210},"(b) ",[200,1008,919],{"class":206},[200,1010,922],{"class":220},[200,1012,905],{"class":210},[200,1014,1016,1018],{"class":202,"line":1015},11,[200,1017,929],{"class":206},[200,1019,1020],{"class":464}," \"\"\n",[200,1022,1024],{"class":202,"line":1023},12,[200,1025,937],{"class":210},[200,1027,1029,1031,1033,1036,1038,1040,1043,1046,1049,1051],{"class":202,"line":1028},13,[200,1030,942],{"class":206},[200,1032,321],{"class":210},[200,1034,1035],{"class":244},"String",[200,1037,236],{"class":210},[200,1039,250],{"class":206},[200,1041,1042],{"class":210},"b[",[200,1044,1045],{"class":220},"0",[200,1047,1048],{"class":210},"], ",[200,1050,958],{"class":244},[200,1052,1053],{"class":210},"(b))\n",[200,1055,1057],{"class":202,"line":1056},14,[200,1058,416],{"class":210},[11,1060,1061,1064,1065,1068],{},[524,1062,1063],{},"Контракт:"," нельзя мутировать полученный ",[29,1066,1067],{},"[]byte"," — строки иммутабельны, нарушишь — undefined behavior. Нельзя сохранять результат дольше, чем живёт исходный буфер, если буфер потом переиспользуется.",[11,1070,1071],{},"Где нужно: hot path с высоким RPS, парсинг логов\u002FJSON, сетевые буферы.",[11,1073,1074],{},"Где не нужно: обычные handler'ы, бизнес-логика, DTO, конфиги, тестовые данные. Копия часто дешевле, чем будущая отладка случайной порчи памяти.",[166,1076,1078,1079,1081],{"id":1077},"каст-byte-struct-бинарные-протоколы","Каст ",[200,1080],{},"byte → struct (бинарные протоколы)",[11,1083,1084,1085,1087],{},"Zero-copy парсинг бинарного протокола — приводим ",[29,1086,1067],{}," к структуре без копирования:",[171,1089,1091],{"className":194,"code":1090,"language":196,"meta":179,"style":179},"type Header struct {\n    Size   uint32\n    Flags  uint16\n    TypeId uint16\n}\n\nfunc Parse(buf []byte) *Header {\n    if len(buf) \u003C int(unsafe.Sizeof(Header{})) {\n        return nil\n    }\n    return (*Header)(unsafe.Pointer(&buf[0]))\n}\n",[29,1092,1093,1106,1114,1122,1129,1133,1137,1162,1189,1195,1199,1226],{"__ignoreMap":179},[200,1094,1095,1098,1101,1104],{"class":202,"line":203},[200,1096,1097],{"class":206},"type",[200,1099,1100],{"class":244}," Header",[200,1102,1103],{"class":206}," struct",[200,1105,905],{"class":210},[200,1107,1108,1111],{"class":202,"line":224},[200,1109,1110],{"class":210},"    Size   ",[200,1112,1113],{"class":206},"uint32\n",[200,1115,1116,1119],{"class":202,"line":307},[200,1117,1118],{"class":210},"    Flags  ",[200,1120,1121],{"class":206},"uint16\n",[200,1123,1124,1127],{"class":202,"line":313},[200,1125,1126],{"class":210},"    TypeId ",[200,1128,1121],{"class":206},[200,1130,1131],{"class":202,"line":332},[200,1132,416],{"class":210},[200,1134,1135],{"class":202,"line":339},[200,1136,336],{"emptyLinePlaceholder":335},[200,1138,1139,1141,1144,1146,1149,1151,1153,1155,1157,1160],{"class":202,"line":345},[200,1140,885],{"class":206},[200,1142,1143],{"class":244}," Parse",[200,1145,236],{"class":210},[200,1147,1148],{"class":893},"buf",[200,1150,986],{"class":210},[200,1152,863],{"class":206},[200,1154,991],{"class":210},[200,1156,430],{"class":206},[200,1158,1159],{"class":244},"Header",[200,1161,905],{"class":210},[200,1163,1164,1166,1168,1171,1174,1177,1179,1182,1184,1186],{"class":202,"line":968},[200,1165,910],{"class":206},[200,1167,913],{"class":244},[200,1169,1170],{"class":210},"(buf) ",[200,1172,1173],{"class":206},"\u003C",[200,1175,1176],{"class":206}," int",[200,1178,292],{"class":210},[200,1180,1181],{"class":244},"Sizeof",[200,1183,236],{"class":210},[200,1185,1159],{"class":244},[200,1187,1188],{"class":210},"{})) {\n",[200,1190,1191,1193],{"class":202,"line":973},[200,1192,929],{"class":206},[200,1194,932],{"class":220},[200,1196,1197],{"class":202,"line":999},[200,1198,937],{"class":210},[200,1200,1201,1203,1206,1208,1210,1212,1214,1216,1218,1221,1223],{"class":202,"line":1015},[200,1202,942],{"class":206},[200,1204,1205],{"class":210}," (",[200,1207,430],{"class":206},[200,1209,1159],{"class":244},[200,1211,241],{"class":210},[200,1213,245],{"class":244},[200,1215,236],{"class":210},[200,1217,250],{"class":206},[200,1219,1220],{"class":210},"buf[",[200,1222,1045],{"class":220},[200,1224,1225],{"class":210},"]))\n",[200,1227,1228],{"class":202,"line":1023},[200,1229,416],{"class":210},[11,1231,1232],{},"Ограничения:",[1234,1235,1236,1240,1243,1253,1256],"ul",{},[1237,1238,1239],"li",{},"struct должен быть без padding-сюрпризов;",[1237,1241,1242],{},"данные должны быть в native endian;",[1237,1244,1245,1246,1249,1250,1252],{},"адрес ",[29,1247,1248],{},"&buf[0]"," должен подходить по alignment для ",[29,1251,1159],{},";",[1237,1254,1255],{},"буфер должен жить дольше, чем возвращённый указатель;",[1237,1257,1258],{},"формат должен быть стабильным между версиями сервиса.",[11,1260,1261],{},"На практике часто безопаснее разобрать поля явно:",[171,1263,1265],{"className":194,"code":1264,"language":196,"meta":179,"style":179},"func ParseSafe(buf []byte) (Header, bool) {\n    if len(buf) \u003C 8 {\n        return Header{}, false\n    }\n\n    return Header{\n        Size:   binary.LittleEndian.Uint32(buf[0:4]),\n        Flags:  binary.LittleEndian.Uint16(buf[4:6]),\n        TypeId: binary.LittleEndian.Uint16(buf[6:8]),\n    }, true\n}\n",[29,1266,1267,1295,1310,1322,1326,1330,1339,1361,1380,1398,1406],{"__ignoreMap":179},[200,1268,1269,1271,1274,1276,1278,1280,1282,1285,1287,1289,1292],{"class":202,"line":203},[200,1270,885],{"class":206},[200,1272,1273],{"class":244}," ParseSafe",[200,1275,236],{"class":210},[200,1277,1148],{"class":893},[200,1279,986],{"class":210},[200,1281,863],{"class":206},[200,1283,1284],{"class":210},") (",[200,1286,1159],{"class":244},[200,1288,506],{"class":210},[200,1290,1291],{"class":206},"bool",[200,1293,1294],{"class":210},") {\n",[200,1296,1297,1299,1301,1303,1305,1308],{"class":202,"line":224},[200,1298,910],{"class":206},[200,1300,913],{"class":244},[200,1302,1170],{"class":210},[200,1304,1173],{"class":206},[200,1306,1307],{"class":220}," 8",[200,1309,905],{"class":210},[200,1311,1312,1314,1316,1319],{"class":202,"line":307},[200,1313,929],{"class":206},[200,1315,1100],{"class":244},[200,1317,1318],{"class":210},"{}, ",[200,1320,1321],{"class":220},"false\n",[200,1323,1324],{"class":202,"line":313},[200,1325,937],{"class":210},[200,1327,1328],{"class":202,"line":332},[200,1329,336],{"emptyLinePlaceholder":335},[200,1331,1332,1334,1336],{"class":202,"line":339},[200,1333,942],{"class":206},[200,1335,1100],{"class":244},[200,1337,1338],{"class":210},"{\n",[200,1340,1341,1344,1347,1350,1352,1355,1358],{"class":202,"line":345},[200,1342,1343],{"class":210},"        Size:   binary.LittleEndian.",[200,1345,1346],{"class":244},"Uint32",[200,1348,1349],{"class":210},"(buf[",[200,1351,1045],{"class":220},[200,1353,1354],{"class":210},":",[200,1356,1357],{"class":220},"4",[200,1359,1360],{"class":210},"]),\n",[200,1362,1363,1366,1369,1371,1373,1375,1378],{"class":202,"line":968},[200,1364,1365],{"class":210},"        Flags:  binary.LittleEndian.",[200,1367,1368],{"class":244},"Uint16",[200,1370,1349],{"class":210},[200,1372,1357],{"class":220},[200,1374,1354],{"class":210},[200,1376,1377],{"class":220},"6",[200,1379,1360],{"class":210},[200,1381,1382,1385,1387,1389,1391,1393,1396],{"class":202,"line":973},[200,1383,1384],{"class":210},"        TypeId: binary.LittleEndian.",[200,1386,1368],{"class":244},[200,1388,1349],{"class":210},[200,1390,1377],{"class":220},[200,1392,1354],{"class":210},[200,1394,1395],{"class":220},"8",[200,1397,1360],{"class":210},[200,1399,1400,1403],{"class":202,"line":999},[200,1401,1402],{"class":210},"    }, ",[200,1404,1405],{"class":220},"true\n",[200,1407,1408],{"class":202,"line":1015},[200,1409,416],{"class":210},[11,1411,1412],{},"Да, это копирует значения. Зато код не зависит от padding, endian и alignment.",[166,1414,1416],{"id":1415},"доступ-к-unexported-полям","Доступ к unexported полям",[11,1418,1419,1420,1422],{},"Через ",[29,1421,583],{}," можно читать\u002Fписать приватные поля чужих структур. Используется в runtime, reflect, тестах. В прикладном коде — red flag.",[166,1424,1426],{"id":1425},"когда-unsafe-бывает-оправдан","Когда unsafe бывает оправдан",[11,1428,1429],{},"Unsafe — не \"ускоритель Go\", а инструмент для случаев, где обычная система типов не выражает нужный контракт.",[11,1431,1432],{},"Оправданные сценарии:",[1234,1434,1435,1438,1441,1444,1447,1450],{},[1237,1436,1437],{},"runtime, компилятор, стандартная библиотека;",[1237,1439,1440],{},"драйверы, syscall, mmap, взаимодействие с C;",[1237,1442,1443],{},"бинарные протоколы с доказанным layout и тестами;",[1237,1445,1446],{},"serialization\u002Fencoding библиотеки, где выигрыш измерен профилем;",[1237,1448,1449],{},"lock-free структуры и atomic-паттерны, когда обычные mutex\u002Fchannel не подходят;",[1237,1451,1452],{},"маленький внутренний API, который закрывает unsafe внутри и отдаёт наружу обычные типы.",[11,1454,1455],{},"Перед добавлением unsafe ответь на три вопроса:",[1457,1458,1459,1462,1465],"ol",{},[1237,1460,1461],{},"Какая конкретная операция слишком дорогая: аллокация, копирование, reflect-call, bounds check?",[1237,1463,1464],{},"Есть ли benchmark до\u002Fпосле и профиль, где видно узкое место?",[1237,1466,1467],{},"Какой контракт должен соблюдать вызывающий код, и где он проверяется?",[11,1469,1470],{},"Если ответа нет хотя бы на один вопрос, unsafe пока рано.",[161,1472,1474],{"id":1473},"когда-не-использовать","Когда НЕ использовать",[1234,1476,1477,1480,1483,1486],{},[1237,1478,1479],{},"Если можно решить без unsafe — решай без unsafe.",[1237,1481,1482],{},"Профилируй сначала: убедись что копирование реально bottleneck.",[1237,1484,1485],{},"Layout чужих структур не является частью публичного API.",[1237,1487,1488,1490],{},[29,1489,799],{}," + fuzz-тесты обязательны для кода с unsafe.",[11,1492,1493],{},"Дополнительные красные флаги:",[1234,1495,1496,1499,1514,1520,1525,1528],{},[1237,1497,1498],{},"unsafe используется ради \"красивого\" доступа к приватному полю;",[1237,1500,1501,1502,506,1504,506,1507,506,1510,1513],{},"код зависит от внутренностей ",[29,1503,994],{},[29,1505,1506],{},"slice",[29,1508,1509],{},"map",[29,1511,1512],{},"interface{}"," без жёсткой причины;",[1237,1515,1516,1517,1519],{},"указатель превращается в ",[29,1518,41],{},", сохраняется в переменную, структуру, map или возвращается из функции;",[1237,1521,1522,1524],{},[29,1523,36],{}," передаётся через goroutine без понятного ownership;",[1237,1526,1527],{},"zero-copy строка указывает на буфер из pool, который потом возвращается обратно;",[1237,1529,1530,1531,506,1534,1536],{},"тесты проверяют только happy path и не гоняют ",[29,1532,1533],{},"-race",[29,1535,799],{},", fuzz или разные размеры буферов.",[161,1538,1540],{"id":1539},"связь-с-reflect-и-generics","Связь с reflect и generics",[11,1542,1543,1544,506,1547,1550,1551,1553],{},"У ",[29,1545,1546],{},"generics",[29,1548,1549],{},"reflect"," и ",[29,1552,468],{}," разные уровни ответственности.",[14,1555,1556,1572],{},[17,1557,1558],{},[20,1559,1560,1563,1566,1569],{},[23,1561,1562],{"align":25},"Инструмент",[23,1564,1565],{"align":25},"Когда выбираем",[23,1567,1568],{"align":25},"Что получаем",[23,1570,1571],{"align":25},"Чем платим",[43,1573,1574,1588,1602,1616],{},[20,1575,1576,1579,1582,1585],{},[48,1577,1578],{"align":25},"Дженерики",[48,1580,1581],{"align":25},"Типы известны на compile-time",[48,1583,1584],{"align":25},"Типобезопасность, меньше дублирования",[48,1586,1587],{"align":25},"Сложные constraints, рост API",[20,1589,1590,1593,1596,1599],{},[48,1591,1592],{"align":25},"Интерфейсы",[48,1594,1595],{"align":25},"Нужен контракт поведения",[48,1597,1598],{"align":25},"Простая подмена реализаций",[48,1600,1601],{"align":25},"Динамический dispatch, меньше информации о concrete type",[20,1603,1604,1607,1610,1613],{},[48,1605,1606],{"align":25},"Reflect",[48,1608,1609],{"align":25},"Типы известны только в runtime",[48,1611,1612],{"align":25},"Универсальность для JSON\u002FORM\u002FDI",[48,1614,1615],{"align":25},"Паники, аллокации, медленнее, меньше compile-time гарантий",[20,1617,1618,1621,1624,1627],{},[48,1619,1620],{"align":25},"Unsafe",[48,1622,1623],{"align":25},"Нужно нарушить модель типов или layout",[48,1625,1626],{"align":25},"Zero-copy, низкоуровневый доступ",[48,1628,1629],{"align":25},"Undefined behavior при нарушении контракта",[11,1631,1632],{},"Хорошая эвристика:",[1234,1634,1635,1638,1643,1649],{},[1237,1636,1637],{},"если можно выразить задачу дженериком — начинай с дженерика;",[1237,1639,1640,1641,1252],{},"если нужен runtime-анализ тегов, полей или методов — используй ",[29,1642,1549],{},[1237,1644,1645,1646,1648],{},"если ",[29,1647,1549],{}," нужен только для обхода типов, но типы известны заранее — скорее всего, нужен generic API;",[1237,1650,1645,1651,1653,1654,1656],{},[29,1652,1549],{}," возвращает ",[29,1655,41],{}," или требует доступа к unexported данным — это уже граница с unsafe, и код должен стать маленьким и хорошо протестированным.",[11,1658,1659],{},"Пример нормального сочетания: наружу отдаём generic-функцию, внутри кешируем metadata через reflect, а unsafe используем только в одном приватном месте.",[171,1661,1663],{"className":194,"code":1662,"language":196,"meta":179,"style":179},"type fieldInfo struct {\n    offset uintptr\n}\n\nfunc Encode[T any](dst []byte, v *T) []byte {\n    \u002F\u002F T даёт типобезопасный публичный API.\n    \u002F\u002F reflect один раз строит metadata по типу.\n    \u002F\u002F unsafe применим только там, где metadata уже проверена.\n    _ = reflect.TypeOf((*T)(nil)).Elem()\n    _ = unsafe.Pointer(v)\n    return dst\n}\n",[29,1664,1665,1676,1684,1688,1692,1733,1738,1743,1748,1784,1797,1804],{"__ignoreMap":179},[200,1666,1667,1669,1672,1674],{"class":202,"line":203},[200,1668,1097],{"class":206},[200,1670,1671],{"class":244}," fieldInfo",[200,1673,1103],{"class":206},[200,1675,905],{"class":210},[200,1677,1678,1681],{"class":202,"line":224},[200,1679,1680],{"class":210},"    offset ",[200,1682,1683],{"class":206},"uintptr\n",[200,1685,1686],{"class":202,"line":307},[200,1687,416],{"class":210},[200,1689,1690],{"class":202,"line":313},[200,1691,336],{"emptyLinePlaceholder":335},[200,1693,1694,1696,1699,1702,1705,1708,1711,1714,1716,1718,1720,1723,1725,1727,1729,1731],{"class":202,"line":332},[200,1695,885],{"class":206},[200,1697,1698],{"class":244}," Encode",[200,1700,1701],{"class":210},"[",[200,1703,1704],{"class":893},"T",[200,1706,1707],{"class":244}," any",[200,1709,1710],{"class":210},"](",[200,1712,1713],{"class":893},"dst",[200,1715,986],{"class":210},[200,1717,863],{"class":206},[200,1719,506],{"class":210},[200,1721,1722],{"class":893},"v",[200,1724,233],{"class":206},[200,1726,1704],{"class":244},[200,1728,900],{"class":210},[200,1730,863],{"class":206},[200,1732,905],{"class":210},[200,1734,1735],{"class":202,"line":339},[200,1736,1737],{"class":256},"    \u002F\u002F T даёт типобезопасный публичный API.\n",[200,1739,1740],{"class":202,"line":345},[200,1741,1742],{"class":256},"    \u002F\u002F reflect один раз строит metadata по типу.\n",[200,1744,1745],{"class":202,"line":968},[200,1746,1747],{"class":256},"    \u002F\u002F unsafe применим только там, где metadata уже проверена.\n",[200,1749,1750,1753,1756,1759,1762,1765,1767,1769,1772,1775,1778,1781],{"class":202,"line":973},[200,1751,1752],{"class":210},"    _ ",[200,1754,1755],{"class":206},"=",[200,1757,1758],{"class":210}," reflect.",[200,1760,1761],{"class":244},"TypeOf",[200,1763,1764],{"class":210},"((",[200,1766,430],{"class":206},[200,1768,1704],{"class":244},[200,1770,1771],{"class":210},")(",[200,1773,1774],{"class":220},"nil",[200,1776,1777],{"class":210},")).",[200,1779,1780],{"class":244},"Elem",[200,1782,1783],{"class":210},"()\n",[200,1785,1786,1788,1790,1792,1794],{"class":202,"line":999},[200,1787,1752],{"class":210},[200,1789,1755],{"class":206},[200,1791,321],{"class":210},[200,1793,245],{"class":244},[200,1795,1796],{"class":210},"(v)\n",[200,1798,1799,1801],{"class":202,"line":1015},[200,1800,942],{"class":206},[200,1802,1803],{"class":210}," dst\n",[200,1805,1806],{"class":202,"line":1023},[200,1807,416],{"class":210},[11,1809,1810,1811,1813],{},"Такой код всё равно требует benchmark и review. Но граница риска понятна: пользователь не видит ",[29,1812,36],{},", а инварианты проверяются рядом с местом нарушения.",[161,1815,1817],{"id":1816},"мостик-к-памяти-и-gc","Мостик к памяти и GC",[11,1819,1820],{},"Unsafe-код почти всегда касается тем из следующих двух уроков.",[166,1822,1824],{"id":1823},"escape-analysis","Escape analysis",[11,1826,1827,1829],{},[29,1828,36],{}," сам по себе не означает \"уйдёт в heap\", но он часто ломает простые рассуждения компилятора. Если указатель сохраняется в интерфейсе, замыкании, глобальном кеше или передаётся в неизвестную функцию, объект может escape'нуться.",[11,1831,1832],{},"Проверяй:",[171,1834,1838],{"className":1835,"code":1836,"language":1837,"meta":179,"style":179},"language-bash shiki shiki-themes github-dark","go build -gcflags=\"-m=2\" .\u002F...\n","bash",[29,1839,1840],{"__ignoreMap":179},[200,1841,1842,1844,1847,1850,1853],{"class":202,"line":203},[200,1843,196],{"class":244},[200,1845,1846],{"class":464}," build",[200,1848,1849],{"class":220}," -gcflags=",[200,1851,1852],{"class":464},"\"-m=2\"",[200,1854,1855],{"class":464}," .\u002F...\n",[11,1857,1858,1859,1862],{},"Ищи не только ",[29,1860,1861],{},"escapes to heap",", но и причину: возврат указателя, interface conversion, closure capture, indirect call.",[166,1864,1866],{"id":1865},"gc-visibility","GC visibility",[11,1868,1869],{},"Главное правило: GC видит Go-указатели, но не видит адреса, спрятанные в числах.",[171,1871,1873],{"className":194,"code":1872,"language":196,"meta":179,"style":179},"type holder struct {\n    addr uintptr \u002F\u002F GC не считает это ссылкой\n}\n\nfunc remember(b []byte) holder {\n    return holder{addr: uintptr(unsafe.Pointer(unsafe.SliceData(b)))}\n}\n",[29,1874,1875,1886,1896,1900,1904,1926,1949],{"__ignoreMap":179},[200,1876,1877,1879,1882,1884],{"class":202,"line":203},[200,1878,1097],{"class":206},[200,1880,1881],{"class":244}," holder",[200,1883,1103],{"class":206},[200,1885,905],{"class":210},[200,1887,1888,1891,1893],{"class":202,"line":224},[200,1889,1890],{"class":210},"    addr ",[200,1892,41],{"class":206},[200,1894,1895],{"class":256}," \u002F\u002F GC не считает это ссылкой\n",[200,1897,1898],{"class":202,"line":307},[200,1899,416],{"class":210},[200,1901,1902],{"class":202,"line":313},[200,1903,336],{"emptyLinePlaceholder":335},[200,1905,1906,1908,1911,1913,1915,1917,1919,1921,1924],{"class":202,"line":332},[200,1907,885],{"class":206},[200,1909,1910],{"class":244}," remember",[200,1912,236],{"class":210},[200,1914,983],{"class":893},[200,1916,986],{"class":210},[200,1918,863],{"class":206},[200,1920,991],{"class":210},[200,1922,1923],{"class":244},"holder",[200,1925,905],{"class":210},[200,1927,1928,1930,1932,1935,1937,1939,1941,1943,1946],{"class":202,"line":339},[200,1929,942],{"class":206},[200,1931,1881],{"class":244},[200,1933,1934],{"class":210},"{addr: ",[200,1936,41],{"class":206},[200,1938,292],{"class":210},[200,1940,245],{"class":244},[200,1942,292],{"class":210},[200,1944,1945],{"class":244},"SliceData",[200,1947,1948],{"class":210},"(b)))}\n",[200,1950,1951],{"class":202,"line":345},[200,1952,416],{"class":210},[11,1954,1955,1956,1958],{},"Такой ",[29,1957,1923],{}," не удерживает underlying array живым. Если нужен lifetime, храни обычную ссылку:",[171,1960,1962],{"className":194,"code":1961,"language":196,"meta":179,"style":179},"type holder struct {\n    buf  []byte\n    addr unsafe.Pointer\n}\n",[29,1963,1964,1974,1982,1993],{"__ignoreMap":179},[200,1965,1966,1968,1970,1972],{"class":202,"line":203},[200,1967,1097],{"class":206},[200,1969,1881],{"class":244},[200,1971,1103],{"class":206},[200,1973,905],{"class":210},[200,1975,1976,1979],{"class":202,"line":224},[200,1977,1978],{"class":210},"    buf  []",[200,1980,1981],{"class":206},"byte\n",[200,1983,1984,1986,1988,1990],{"class":202,"line":307},[200,1985,1890],{"class":210},[200,1987,468],{"class":244},[200,1989,154],{"class":210},[200,1991,1992],{"class":244},"Pointer\n",[200,1994,1995],{"class":202,"line":313},[200,1996,416],{"class":210},[11,1998,1999,2000,2003,2004,2007],{},"Иногда нужен ",[29,2001,2002],{},"runtime.KeepAlive(x)",": он явно сообщает компилятору, что ",[29,2005,2006],{},"x"," должен считаться живым до этой строки.",[171,2009,2011],{"className":194,"code":2010,"language":196,"meta":179,"style":179},"func write(fd uintptr, b []byte) {\n    p := unsafe.Pointer(unsafe.SliceData(b))\n    syscall.Syscall(SYS_WRITE, fd, uintptr(p), uintptr(len(b)))\n    runtime.KeepAlive(b)\n}\n",[29,2012,2013,2037,2054,2078,2089],{"__ignoreMap":179},[200,2014,2015,2017,2020,2022,2025,2027,2029,2031,2033,2035],{"class":202,"line":203},[200,2016,885],{"class":206},[200,2018,2019],{"class":244}," write",[200,2021,236],{"class":210},[200,2023,2024],{"class":893},"fd",[200,2026,289],{"class":206},[200,2028,506],{"class":210},[200,2030,983],{"class":893},[200,2032,986],{"class":210},[200,2034,863],{"class":206},[200,2036,1294],{"class":210},[200,2038,2039,2042,2044,2046,2048,2050,2052],{"class":202,"line":224},[200,2040,2041],{"class":210},"    p ",[200,2043,230],{"class":206},[200,2045,321],{"class":210},[200,2047,245],{"class":244},[200,2049,292],{"class":210},[200,2051,1945],{"class":244},[200,2053,1053],{"class":210},[200,2055,2056,2059,2061,2064,2066,2069,2071,2073,2075],{"class":202,"line":307},[200,2057,2058],{"class":210},"    syscall.",[200,2060,694],{"class":244},[200,2062,2063],{"class":210},"(SYS_WRITE, fd, ",[200,2065,41],{"class":206},[200,2067,2068],{"class":210},"(p), ",[200,2070,41],{"class":206},[200,2072,236],{"class":210},[200,2074,958],{"class":244},[200,2076,2077],{"class":210},"(b)))\n",[200,2079,2080,2083,2086],{"class":202,"line":313},[200,2081,2082],{"class":210},"    runtime.",[200,2084,2085],{"class":244},"KeepAlive",[200,2087,2088],{"class":210},"(b)\n",[200,2090,2091],{"class":202,"line":332},[200,2092,416],{"class":210},[11,2094,2095,2097,2098,2100],{},[29,2096,2085],{}," не делает плохой ",[29,2099,41],{}," хорошим. Он только фиксирует lifetime исходного Go-объекта до конкретной точки.",[166,2102,2104],{"id":2103},"аллокатор-и-alignment","Аллокатор и alignment",[11,2106,1078,2107,2109,2110,2113],{},[29,2108,1067],{}," в ",[29,2111,2112],{},"*Header"," может быть логически верным по размеру, но неверным по alignment. На одних архитектурах unaligned access просто медленнее, на других может падать или давать некорректное поведение.",[11,2115,2116],{},"Проверяй layout явно:",[171,2118,2120],{"className":194,"code":2119,"language":196,"meta":179,"style":179},"const headerSize = unsafe.Sizeof(Header{})\nconst headerAlign = unsafe.Alignof(Header{})\n\nfunc aligned(p unsafe.Pointer) bool {\n    return uintptr(p)%headerAlign == 0\n}\n",[29,2121,2122,2143,2163,2167,2191,2211],{"__ignoreMap":179},[200,2123,2124,2127,2130,2132,2134,2136,2138,2140],{"class":202,"line":203},[200,2125,2126],{"class":206},"const",[200,2128,2129],{"class":220}," headerSize",[200,2131,217],{"class":206},[200,2133,321],{"class":210},[200,2135,1181],{"class":244},[200,2137,236],{"class":210},[200,2139,1159],{"class":244},[200,2141,2142],{"class":210},"{})\n",[200,2144,2145,2147,2150,2152,2154,2157,2159,2161],{"class":202,"line":224},[200,2146,2126],{"class":206},[200,2148,2149],{"class":220}," headerAlign",[200,2151,217],{"class":206},[200,2153,321],{"class":210},[200,2155,2156],{"class":244},"Alignof",[200,2158,236],{"class":210},[200,2160,1159],{"class":244},[200,2162,2142],{"class":210},[200,2164,2165],{"class":202,"line":307},[200,2166,336],{"emptyLinePlaceholder":335},[200,2168,2169,2171,2174,2176,2178,2181,2183,2185,2187,2189],{"class":202,"line":313},[200,2170,885],{"class":206},[200,2172,2173],{"class":244}," aligned",[200,2175,236],{"class":210},[200,2177,11],{"class":893},[200,2179,2180],{"class":244}," unsafe",[200,2182,154],{"class":210},[200,2184,245],{"class":244},[200,2186,991],{"class":210},[200,2188,1291],{"class":206},[200,2190,905],{"class":210},[200,2192,2193,2195,2197,2200,2203,2206,2208],{"class":202,"line":332},[200,2194,942],{"class":206},[200,2196,289],{"class":206},[200,2198,2199],{"class":210},"(p)",[200,2201,2202],{"class":206},"%",[200,2204,2205],{"class":210},"headerAlign ",[200,2207,919],{"class":206},[200,2209,2210],{"class":220}," 0\n",[200,2212,2213],{"class":202,"line":339},[200,2214,416],{"class":210},[11,2216,2217,2218,2221],{},"Если формат приходит из сети или файла, обычно лучше читать поля через ",[29,2219,2220],{},"encoding\u002Fbinary",", а unsafe оставить для строго контролируемого in-memory формата.",[161,2223,2225],{"id":2224},"задания-на-ревью-кода","Задания на ревью кода",[11,2227,2228],{},"Ниже код, который выглядит \"производительно\". Найди проблемы и предложи безопасную версию.",[166,2230,2232,2233,863],{"id":2231},"задание-1-string-to-byte","Задание 1: string to ",[200,2234],{},[171,2236,2238],{"className":194,"code":2237,"language":196,"meta":179,"style":179},"func Bytes(s string) []byte {\n    return unsafe.Slice(unsafe.StringData(s), len(s))\n}\n\nfunc Normalize(s string) string {\n    b := Bytes(s)\n    for i := range b {\n        if b[i] >= 'A' && b[i] \u003C= 'Z' {\n            b[i] += 'a' - 'A'\n        }\n    }\n    return unsafe.String(&b[0], len(b))\n}\n",[29,2239,2240,2259,2277,2281,2285,2304,2316,2331,2368,2393,2398,2402,2424],{"__ignoreMap":179},[200,2241,2242,2244,2247,2249,2251,2253,2255,2257],{"class":202,"line":203},[200,2243,885],{"class":206},[200,2245,2246],{"class":244}," Bytes",[200,2248,236],{"class":210},[200,2250,894],{"class":893},[200,2252,897],{"class":206},[200,2254,900],{"class":210},[200,2256,863],{"class":206},[200,2258,905],{"class":210},[200,2260,2261,2263,2265,2267,2269,2271,2273,2275],{"class":202,"line":224},[200,2262,942],{"class":206},[200,2264,321],{"class":210},[200,2266,947],{"class":244},[200,2268,292],{"class":210},[200,2270,952],{"class":244},[200,2272,955],{"class":210},[200,2274,958],{"class":244},[200,2276,961],{"class":210},[200,2278,2279],{"class":202,"line":307},[200,2280,416],{"class":210},[200,2282,2283],{"class":202,"line":313},[200,2284,336],{"emptyLinePlaceholder":335},[200,2286,2287,2289,2292,2294,2296,2298,2300,2302],{"class":202,"line":332},[200,2288,885],{"class":206},[200,2290,2291],{"class":244}," Normalize",[200,2293,236],{"class":210},[200,2295,894],{"class":893},[200,2297,897],{"class":206},[200,2299,991],{"class":210},[200,2301,994],{"class":206},[200,2303,905],{"class":210},[200,2305,2306,2309,2311,2313],{"class":202,"line":339},[200,2307,2308],{"class":210},"    b ",[200,2310,230],{"class":206},[200,2312,2246],{"class":244},[200,2314,2315],{"class":210},"(s)\n",[200,2317,2318,2321,2323,2325,2328],{"class":202,"line":345},[200,2319,2320],{"class":206},"    for",[200,2322,211],{"class":210},[200,2324,230],{"class":206},[200,2326,2327],{"class":206}," range",[200,2329,2330],{"class":210}," b {\n",[200,2332,2333,2336,2339,2342,2345,2348,2351,2354,2356,2359,2361,2364,2366],{"class":202,"line":968},[200,2334,2335],{"class":206},"        if",[200,2337,2338],{"class":210}," b[i] ",[200,2340,2341],{"class":206},">=",[200,2343,2344],{"class":464}," '",[200,2346,2347],{"class":220},"A",[200,2349,2350],{"class":464},"'",[200,2352,2353],{"class":206}," &&",[200,2355,2338],{"class":210},[200,2357,2358],{"class":206},"\u003C=",[200,2360,2344],{"class":464},[200,2362,2363],{"class":220},"Z",[200,2365,2350],{"class":464},[200,2367,905],{"class":210},[200,2369,2370,2373,2376,2378,2381,2383,2386,2388,2390],{"class":202,"line":973},[200,2371,2372],{"class":210},"            b[i] ",[200,2374,2375],{"class":206},"+=",[200,2377,2344],{"class":464},[200,2379,2380],{"class":220},"a",[200,2382,2350],{"class":464},[200,2384,2385],{"class":206}," -",[200,2387,2344],{"class":464},[200,2389,2347],{"class":220},[200,2391,2392],{"class":464},"'\n",[200,2394,2395],{"class":202,"line":999},[200,2396,2397],{"class":210},"        }\n",[200,2399,2400],{"class":202,"line":1015},[200,2401,937],{"class":210},[200,2403,2404,2406,2408,2410,2412,2414,2416,2418,2420,2422],{"class":202,"line":1023},[200,2405,942],{"class":206},[200,2407,321],{"class":210},[200,2409,1035],{"class":244},[200,2411,236],{"class":210},[200,2413,250],{"class":206},[200,2415,1042],{"class":210},[200,2417,1045],{"class":220},[200,2419,1048],{"class":210},[200,2421,958],{"class":244},[200,2423,1053],{"class":210},[200,2425,2426],{"class":202,"line":1028},[200,2427,416],{"class":210},[11,2429,2430],{},"Что проверить:",[1234,2432,2433,2436,2439,2442],{},[1237,2434,2435],{},"что произойдёт с пустой строкой;",[1237,2437,2438],{},"можно ли мутировать память строки;",[1237,2440,2441],{},"нужна ли здесь zero-copy конверсия вообще;",[1237,2443,2444,2445,154],{},"как написать benchmark для обычного ",[29,2446,869],{},[166,2448,2450],{"id":2449},"задание-2-uintptr-в-структуре","Задание 2: uintptr в структуре",[171,2452,2454],{"className":194,"code":2453,"language":196,"meta":179,"style":179},"type cacheEntry struct {\n    addr uintptr\n    size int\n}\n\nfunc NewEntry(buf []byte) cacheEntry {\n    return cacheEntry{\n        addr: uintptr(unsafe.Pointer(&buf[0])),\n        size: len(buf),\n    }\n}\n\nfunc (e cacheEntry) Bytes() []byte {\n    return unsafe.Slice((*byte)(unsafe.Pointer(e.addr)), e.size)\n}\n",[29,2455,2456,2467,2473,2481,2485,2489,2511,2519,2541,2551,2555,2559,2563,2586,2606],{"__ignoreMap":179},[200,2457,2458,2460,2463,2465],{"class":202,"line":203},[200,2459,1097],{"class":206},[200,2461,2462],{"class":244}," cacheEntry",[200,2464,1103],{"class":206},[200,2466,905],{"class":210},[200,2468,2469,2471],{"class":202,"line":224},[200,2470,1890],{"class":210},[200,2472,1683],{"class":206},[200,2474,2475,2478],{"class":202,"line":307},[200,2476,2477],{"class":210},"    size ",[200,2479,2480],{"class":206},"int\n",[200,2482,2483],{"class":202,"line":313},[200,2484,416],{"class":210},[200,2486,2487],{"class":202,"line":332},[200,2488,336],{"emptyLinePlaceholder":335},[200,2490,2491,2493,2496,2498,2500,2502,2504,2506,2509],{"class":202,"line":339},[200,2492,885],{"class":206},[200,2494,2495],{"class":244}," NewEntry",[200,2497,236],{"class":210},[200,2499,1148],{"class":893},[200,2501,986],{"class":210},[200,2503,863],{"class":206},[200,2505,991],{"class":210},[200,2507,2508],{"class":244},"cacheEntry",[200,2510,905],{"class":210},[200,2512,2513,2515,2517],{"class":202,"line":345},[200,2514,942],{"class":206},[200,2516,2462],{"class":244},[200,2518,1338],{"class":210},[200,2520,2521,2524,2526,2528,2530,2532,2534,2536,2538],{"class":202,"line":968},[200,2522,2523],{"class":210},"        addr: ",[200,2525,41],{"class":206},[200,2527,292],{"class":210},[200,2529,245],{"class":244},[200,2531,236],{"class":210},[200,2533,250],{"class":206},[200,2535,1220],{"class":210},[200,2537,1045],{"class":220},[200,2539,2540],{"class":210},"])),\n",[200,2542,2543,2546,2548],{"class":202,"line":973},[200,2544,2545],{"class":210},"        size: ",[200,2547,958],{"class":244},[200,2549,2550],{"class":210},"(buf),\n",[200,2552,2553],{"class":202,"line":999},[200,2554,937],{"class":210},[200,2556,2557],{"class":202,"line":1015},[200,2558,416],{"class":210},[200,2560,2561],{"class":202,"line":1023},[200,2562,336],{"emptyLinePlaceholder":335},[200,2564,2565,2567,2569,2572,2574,2576,2579,2582,2584],{"class":202,"line":1028},[200,2566,885],{"class":206},[200,2568,1205],{"class":210},[200,2570,2571],{"class":893},"e ",[200,2573,2508],{"class":244},[200,2575,991],{"class":210},[200,2577,2578],{"class":244},"Bytes",[200,2580,2581],{"class":210},"() []",[200,2583,863],{"class":206},[200,2585,905],{"class":210},[200,2587,2588,2590,2592,2594,2596,2599,2601,2603],{"class":202,"line":1056},[200,2589,942],{"class":206},[200,2591,321],{"class":210},[200,2593,947],{"class":244},[200,2595,1764],{"class":210},[200,2597,2598],{"class":206},"*byte",[200,2600,241],{"class":210},[200,2602,245],{"class":244},[200,2604,2605],{"class":210},"(e.addr)), e.size)\n",[200,2607,2609],{"class":202,"line":2608},15,[200,2610,416],{"class":210},[11,2612,2430],{},[1234,2614,2615,2621,2627,2633],{},[1237,2616,2617,2618,2620],{},"кто удерживает ",[29,2619,1148],{}," живым;",[1237,2622,2623,2624,1252],{},"что будет при ",[29,2625,2626],{},"len(buf) == 0",[1237,2628,2629,2630,1252],{},"можно ли вернуть буфер в ",[29,2631,2632],{},"sync.Pool",[1237,2634,2635,2636,2639,2640,2642,2643,2645],{},"почему ",[29,2637,2638],{},"addr uintptr"," хуже, чем хранить ",[29,2641,1067],{}," или ",[29,2644,36],{}," рядом с owner.",[166,2647,2649],{"id":2648},"задание-3-binary-header","Задание 3: binary header",[171,2651,2653],{"className":194,"code":2652,"language":196,"meta":179,"style":179},"type Header struct {\n    Version byte\n    Size    uint32\n    Flags   uint16\n}\n\nfunc ParseHeader(b []byte) Header {\n    return *(*Header)(unsafe.Pointer(&b[0]))\n}\n",[29,2654,2655,2665,2672,2679,2686,2690,2694,2715,2741],{"__ignoreMap":179},[200,2656,2657,2659,2661,2663],{"class":202,"line":203},[200,2658,1097],{"class":206},[200,2660,1100],{"class":244},[200,2662,1103],{"class":206},[200,2664,905],{"class":210},[200,2666,2667,2670],{"class":202,"line":224},[200,2668,2669],{"class":210},"    Version ",[200,2671,1981],{"class":206},[200,2673,2674,2677],{"class":202,"line":307},[200,2675,2676],{"class":210},"    Size    ",[200,2678,1113],{"class":206},[200,2680,2681,2684],{"class":202,"line":313},[200,2682,2683],{"class":210},"    Flags   ",[200,2685,1121],{"class":206},[200,2687,2688],{"class":202,"line":332},[200,2689,416],{"class":210},[200,2691,2692],{"class":202,"line":339},[200,2693,336],{"emptyLinePlaceholder":335},[200,2695,2696,2698,2701,2703,2705,2707,2709,2711,2713],{"class":202,"line":345},[200,2697,885],{"class":206},[200,2699,2700],{"class":244}," ParseHeader",[200,2702,236],{"class":210},[200,2704,983],{"class":893},[200,2706,986],{"class":210},[200,2708,863],{"class":206},[200,2710,991],{"class":210},[200,2712,1159],{"class":244},[200,2714,905],{"class":210},[200,2716,2717,2719,2721,2723,2725,2727,2729,2731,2733,2735,2737,2739],{"class":202,"line":968},[200,2718,942],{"class":206},[200,2720,233],{"class":206},[200,2722,236],{"class":210},[200,2724,430],{"class":206},[200,2726,1159],{"class":244},[200,2728,241],{"class":210},[200,2730,245],{"class":244},[200,2732,236],{"class":210},[200,2734,250],{"class":206},[200,2736,1042],{"class":210},[200,2738,1045],{"class":220},[200,2740,1225],{"class":210},[200,2742,2743],{"class":202,"line":973},[200,2744,416],{"class":210},[11,2746,2430],{},[1234,2748,2749,2752,2755,2761,2764],{},[1237,2750,2751],{},"размер структуры с padding;",[1237,2753,2754],{},"endian входных данных;",[1237,2756,2757,2758,1252],{},"alignment ",[29,2759,2760],{},"&b[0]",[1237,2762,2763],{},"поведение на коротком буфере;",[1237,2765,2766],{},"нужен ли здесь pointer receiver или достаточно вернуть значения.",[161,2768,2770],{"id":2769},"чеклист-собеседования","Чеклист собеседования",[11,2772,2773,2774,2776],{},"Если на интервью спрашивают про ",[29,2775,468],{},", хороший ответ не должен звучать как \"можно всё\". Лучше показать границы.",[1234,2778,2779,2784,2791,2796,2804,2813,2830,2836,2843,2849],{},[1237,2780,2781,2783],{},[29,2782,36],{}," — указатель без типа; его нельзя разыменовать напрямую.",[1237,2785,2786,2788,2789,154],{},[29,2787,41],{}," — число, не ссылка; GC не удерживает объект по ",[29,2790,41],{},[1237,2792,2793,2795],{},[29,2794,41],{},"-арифметика допустима только в разрешённых паттернах, чаще всего в одном выражении.",[1237,2797,2798,2800,2801,154],{},[29,2799,638],{}," предпочтительнее ручного ",[29,2802,2803],{},"uintptr(...) + offset",[1237,2805,2806,506,2808,506,2810,2812],{},[29,2807,1181],{},[29,2809,2156],{},[29,2811,583],{}," вычисляются на compile-time и описывают layout, но не делают layout переносимым протоколом.",[1237,2814,2815,1550,2818,2821,2822,506,2824,506,2826,506,2828,154],{},[29,2816,2817],{},"SliceHeader",[29,2819,2820],{},"StringHeader"," не использовать для нового кода; есть ",[29,2823,774],{},[29,2825,952],{},[29,2827,947],{},[29,2829,1945],{},[1237,2831,2832,2833,2835],{},"Zero-copy string\u002F",[200,2834],{},"byte требует строгого ownership: не мутировать string, не переиспользовать буфер раньше времени.",[1237,2837,2838,1653,2840,2842],{},[29,2839,725],{},[29,2841,41],{},"; это ловушка для lifetime.",[1237,2844,2845,2848],{},[29,2846,2847],{},"runtime.KeepAlive"," нужен, когда компилятор может посчитать объект мёртвым раньше внешнего вызова.",[1237,2850,2851,2852,2854],{},"Любой unsafe-код должен быть маленьким, закрытым за обычным API, покрытым ",[29,2853,799],{},", тестами, fuzz\u002Fbenchmark по необходимости.",[376,2856],{},[161,2858,2860],{"id":2859},"практика","Практика",[2862,2863,2867,2873,2901],"quiz",{"answer":2864,"id":2865,"xp":2866},"2","advanced-unsafe-q1","10",[11,2868,2869,2870,2872],{},"Почему опасно хранить адрес Go-объекта только как ",[29,2871,41],{},"?",[2874,2875,2876],"template",{"v-slot:options":179},[1234,2877,2878,2883,2888,2896],{},[1237,2879,2880,2882],{},[29,2881,41],{}," всегда занимает меньше байт, чем указатель",[1237,2884,2885,2887],{},[29,2886,41],{}," — число, а не ссылка; GC не обязан считать объект живым из-за такого значения",[1237,2889,2890,2892,2893],{},[29,2891,41],{}," нельзя печатать через ",[29,2894,2895],{},"fmt",[1237,2897,2898,2900],{},[29,2899,41],{}," автоматически выравнивает адрес по размеру cache line",[2874,2902,2903],{"v-slot:explanation":179},[11,2904,2905,2907,2908,2910,2911,2913],{},[29,2906,41],{}," не является указателем для сборщика мусора. Если рядом нет настоящей ссылки на объект, GC может переместить lifetime объекта раньше, чем код снова превратит число в ",[29,2909,36],{},". Поэтому ",[29,2912,41],{},"-арифметику держат короткой и обычно в одном выражении.",[2915,2916,2919,2922,3037],"predict",{"answer":1395,"id":2917,"xp":2918},"advanced-unsafe-p1","15",[11,2920,2921],{},"Что выведет программа на обычной Go-архитектуре?",[2874,2923,2924],{"v-slot:code":179},[171,2925,2927],{"className":194,"code":2926,"language":196,"meta":179,"style":179},"package main\n\nimport (\n    \"fmt\"\n    \"unsafe\"\n)\n\ntype Header struct {\n    Version byte\n    Size    uint32\n}\n\nfunc main() {\n    fmt.Println(unsafe.Sizeof(Header{}))\n}\n",[29,2928,2929,2937,2941,2948,2957,2965,2970,2974,2984,2990,2996,3000,3004,3014,3033],{"__ignoreMap":179},[200,2930,2931,2934],{"class":202,"line":203},[200,2932,2933],{"class":206},"package",[200,2935,2936],{"class":244}," main\n",[200,2938,2939],{"class":202,"line":224},[200,2940,336],{"emptyLinePlaceholder":335},[200,2942,2943,2945],{"class":202,"line":307},[200,2944,461],{"class":206},[200,2946,2947],{"class":210}," (\n",[200,2949,2950,2953,2955],{"class":202,"line":313},[200,2951,2952],{"class":464},"    \"",[200,2954,2895],{"class":244},[200,2956,471],{"class":464},[200,2958,2959,2961,2963],{"class":202,"line":332},[200,2960,2952],{"class":464},[200,2962,468],{"class":244},[200,2964,471],{"class":464},[200,2966,2967],{"class":202,"line":339},[200,2968,2969],{"class":210},")\n",[200,2971,2972],{"class":202,"line":345},[200,2973,336],{"emptyLinePlaceholder":335},[200,2975,2976,2978,2980,2982],{"class":202,"line":968},[200,2977,1097],{"class":206},[200,2979,1100],{"class":244},[200,2981,1103],{"class":206},[200,2983,905],{"class":210},[200,2985,2986,2988],{"class":202,"line":973},[200,2987,2669],{"class":210},[200,2989,1981],{"class":206},[200,2991,2992,2994],{"class":202,"line":999},[200,2993,2676],{"class":210},[200,2995,1113],{"class":206},[200,2997,2998],{"class":202,"line":1015},[200,2999,416],{"class":210},[200,3001,3002],{"class":202,"line":1023},[200,3003,336],{"emptyLinePlaceholder":335},[200,3005,3006,3008,3011],{"class":202,"line":1028},[200,3007,885],{"class":206},[200,3009,3010],{"class":244}," main",[200,3012,3013],{"class":210},"() {\n",[200,3015,3016,3019,3022,3024,3026,3028,3030],{"class":202,"line":1056},[200,3017,3018],{"class":210},"    fmt.",[200,3020,3021],{"class":244},"Println",[200,3023,292],{"class":210},[200,3025,1181],{"class":244},[200,3027,236],{"class":210},[200,3029,1159],{"class":244},[200,3031,3032],{"class":210},"{}))\n",[200,3034,3035],{"class":202,"line":2608},[200,3036,416],{"class":210},[2874,3038,3039],{"v-slot:hint":179},[11,3040,3041,3042,3044,3045,3048],{},"После ",[29,3043,863],{}," компилятор добавляет padding, чтобы ",[29,3046,3047],{},"uint32"," лежал по адресу, кратному 4. Поэтому структура занимает не 5, а 8 байт.",[3050,3051,3055,3073,3287],"code-task",{"expected":3052,"id":3053,"xp":3054},"513\\nfalse","advanced-unsafe-ct1","20",[11,3056,3057,3058,3060,3061,3063,3064,3067,3068,1550,3070,154],{},"Перепиши чтение ",[29,3059,3047],{}," из байтов без ",[29,3062,468],{},". Функция должна вернуть значение и ",[29,3065,3066],{},"true",", если в буфере хватает 4 байт, иначе ",[29,3069,1045],{},[29,3071,3072],{},"false",[2874,3074,3075],{"v-slot:template":179},[171,3076,3078],{"className":194,"code":3077,"language":196,"meta":179,"style":179},"package main\n\nimport (\n    \"encoding\u002Fbinary\"\n    \"fmt\"\n)\n\nfunc ReadUint32LE(b []byte) (uint32, bool) {\n    return 0, false\n}\n\nfunc main() {\n    n, ok := ReadUint32LE([]byte{1, 2, 0, 0})\n    if ok {\n        fmt.Println(n)\n    }\n\n    _, ok = ReadUint32LE([]byte{1, 2})\n    fmt.Println(ok)\n\n    _ = binary.LittleEndian\n}\n",[29,3079,3080,3086,3090,3096,3104,3112,3116,3120,3145,3155,3159,3163,3171,3206,3213,3223,3228,3233,3257,3267,3272,3282],{"__ignoreMap":179},[200,3081,3082,3084],{"class":202,"line":203},[200,3083,2933],{"class":206},[200,3085,2936],{"class":244},[200,3087,3088],{"class":202,"line":224},[200,3089,336],{"emptyLinePlaceholder":335},[200,3091,3092,3094],{"class":202,"line":307},[200,3093,461],{"class":206},[200,3095,2947],{"class":210},[200,3097,3098,3100,3102],{"class":202,"line":313},[200,3099,2952],{"class":464},[200,3101,2220],{"class":244},[200,3103,471],{"class":464},[200,3105,3106,3108,3110],{"class":202,"line":332},[200,3107,2952],{"class":464},[200,3109,2895],{"class":244},[200,3111,471],{"class":464},[200,3113,3114],{"class":202,"line":339},[200,3115,2969],{"class":210},[200,3117,3118],{"class":202,"line":345},[200,3119,336],{"emptyLinePlaceholder":335},[200,3121,3122,3124,3127,3129,3131,3133,3135,3137,3139,3141,3143],{"class":202,"line":968},[200,3123,885],{"class":206},[200,3125,3126],{"class":244}," ReadUint32LE",[200,3128,236],{"class":210},[200,3130,983],{"class":893},[200,3132,986],{"class":210},[200,3134,863],{"class":206},[200,3136,1284],{"class":210},[200,3138,3047],{"class":206},[200,3140,506],{"class":210},[200,3142,1291],{"class":206},[200,3144,1294],{"class":210},[200,3146,3147,3149,3151,3153],{"class":202,"line":973},[200,3148,942],{"class":206},[200,3150,922],{"class":220},[200,3152,506],{"class":210},[200,3154,1321],{"class":220},[200,3156,3157],{"class":202,"line":999},[200,3158,416],{"class":210},[200,3160,3161],{"class":202,"line":1015},[200,3162,336],{"emptyLinePlaceholder":335},[200,3164,3165,3167,3169],{"class":202,"line":1023},[200,3166,885],{"class":206},[200,3168,3010],{"class":244},[200,3170,3013],{"class":210},[200,3172,3173,3176,3178,3180,3183,3185,3188,3191,3193,3195,3197,3199,3201,3203],{"class":202,"line":1028},[200,3174,3175],{"class":210},"    n, ok ",[200,3177,230],{"class":206},[200,3179,3126],{"class":244},[200,3181,3182],{"class":210},"([]",[200,3184,863],{"class":206},[200,3186,3187],{"class":210},"{",[200,3189,3190],{"class":220},"1",[200,3192,506],{"class":210},[200,3194,2864],{"class":220},[200,3196,506],{"class":210},[200,3198,1045],{"class":220},[200,3200,506],{"class":210},[200,3202,1045],{"class":220},[200,3204,3205],{"class":210},"})\n",[200,3207,3208,3210],{"class":202,"line":1056},[200,3209,910],{"class":206},[200,3211,3212],{"class":210}," ok {\n",[200,3214,3215,3218,3220],{"class":202,"line":2608},[200,3216,3217],{"class":210},"        fmt.",[200,3219,3021],{"class":244},[200,3221,3222],{"class":210},"(n)\n",[200,3224,3226],{"class":202,"line":3225},16,[200,3227,937],{"class":210},[200,3229,3231],{"class":202,"line":3230},17,[200,3232,336],{"emptyLinePlaceholder":335},[200,3234,3236,3239,3241,3243,3245,3247,3249,3251,3253,3255],{"class":202,"line":3235},18,[200,3237,3238],{"class":210},"    _, ok ",[200,3240,1755],{"class":206},[200,3242,3126],{"class":244},[200,3244,3182],{"class":210},[200,3246,863],{"class":206},[200,3248,3187],{"class":210},[200,3250,3190],{"class":220},[200,3252,506],{"class":210},[200,3254,2864],{"class":220},[200,3256,3205],{"class":210},[200,3258,3260,3262,3264],{"class":202,"line":3259},19,[200,3261,3018],{"class":210},[200,3263,3021],{"class":244},[200,3265,3266],{"class":210},"(ok)\n",[200,3268,3270],{"class":202,"line":3269},20,[200,3271,336],{"emptyLinePlaceholder":335},[200,3273,3275,3277,3279],{"class":202,"line":3274},21,[200,3276,1752],{"class":210},[200,3278,1755],{"class":206},[200,3280,3281],{"class":210}," binary.LittleEndian\n",[200,3283,3285],{"class":202,"line":3284},22,[200,3286,416],{"class":210},[2874,3288,3289],{"v-slot:hints":179},[1234,3290,3291,3297,3303],{},[1237,3292,3293,3294],{},"Сначала проверь ",[29,3295,3296],{},"len(b) \u003C 4",[1237,3298,3299,3300],{},"Для корректного endian используй ",[29,3301,3302],{},"binary.LittleEndian.Uint32(b)",[1237,3304,3305,3306,3309],{},"Последняя строка в ",[29,3307,3308],{},"main"," нужна только чтобы импорт не считался лишним до твоей реализации",[3311,3312,3313],"style",{},"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 .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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 .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":179,"searchDepth":224,"depth":224,"links":3315},[3316,3327,3335,3336,3337,3342,3348,3349],{"id":163,"depth":224,"text":164,"children":3317},[3318,3319,3320,3321,3322,3323,3324,3325,3326],{"id":168,"depth":307,"text":169},{"id":260,"depth":307,"text":261},{"id":383,"depth":307,"text":384},{"id":450,"depth":307,"text":451},{"id":530,"depth":307,"text":531},{"id":673,"depth":307,"text":674},{"id":719,"depth":307,"text":720},{"id":798,"depth":307,"text":799},{"id":815,"depth":307,"text":816},{"id":855,"depth":224,"text":856,"children":3328},[3329,3331,3333,3334],{"id":859,"depth":307,"text":3330},"Zero-copy string ↔ byte",{"id":1077,"depth":307,"text":3332},"Каст byte → struct (бинарные протоколы)",{"id":1415,"depth":307,"text":1416},{"id":1425,"depth":307,"text":1426},{"id":1473,"depth":224,"text":1474},{"id":1539,"depth":224,"text":1540},{"id":1816,"depth":224,"text":1817,"children":3338},[3339,3340,3341],{"id":1823,"depth":307,"text":1824},{"id":1865,"depth":307,"text":1866},{"id":2103,"depth":307,"text":2104},{"id":2224,"depth":224,"text":2225,"children":3343},[3344,3346,3347],{"id":2231,"depth":307,"text":3345},"Задание 1: string to byte",{"id":2449,"depth":307,"text":2450},{"id":2648,"depth":307,"text":2649},{"id":2769,"depth":224,"text":2770},{"id":2859,"depth":224,"text":2860},1781458311675]