[{"data":1,"prerenderedAt":8401},["ShallowReactive",2],{"content:\u002F04-advanced\u002F01-generics-reflect":3},{"title":4,"description":5,"path":6,"body":7},"Дженерики и рефлексия","","\u002F04-advanced\u002F01-generics-reflect",{"type":8,"value":9,"toc":8315},"minimark",[10,41,44,49,54,58,209,213,338,342,346,405,408,411,413,474,476,480,484,523,533,537,598,604,608,777,780,784,937,940,944,1010,1023,1032,1034,1070,1072,1076,1080,1165,1169,1282,1285,1289,1360,1363,1367,1524,1534,1536,1580,1582,1586,1590,1709,1712,1716,1780,1783,1787,1822,1825,1829,1922,1932,1936,2075,2089,2093,2161,2176,2182,2303,2311,2315,2452,2462,2464,2502,2504,2508,2512,2782,2797,2801,2913,2934,2938,2988,2991,2995,3081,3084,3088,3220,3223,3227,3359,3368,3370,3416,3418,3422,3426,3592,3596,3599,3602,3607,3611,3698,3712,3716,3719,3722,3726,3733,3736,3738,3791,3793,3797,3801,3805,3867,3882,3886,4020,4028,4032,4225,4248,4261,4265,4268,4276,4280,4391,4400,4402,4454,4456,4460,4464,4699,4706,4710,4866,4873,4877,5221,5229,5233,5328,5331,5335,5462,5471,5475,5590,5596,5598,5636,5638,5642,5646,5751,5757,5760,5829,5832,5835,5838,5841,5844,5848,5963,5969,5973,5977,6108,6118,6120,6153,6155,6159,6162,6235,6238,6242,6362,6365,6369,6489,6492,6496,6583,6591,6595,6659,6667,6671,6674,6677,6680,6683,6685,6722,6724,6728,6732,6782,6793,6806,6810,7003,7020,7024,7113,7128,7132,7238,7244,7248,7370,7382,7384,7427,7429,7433,7437,7443,7448,7452,7544,7550,7554,7686,7697,7701,7822,7826,7881,7884,7886,7890,7929,8071,8311],[11,12,13,22,29,35,38],"ul",{},[14,15,16,17,21],"li",{},"проблема: одинаковый код для разных типов → ",[18,19,20],"strong",{},"дублирование"," (maxInt, maxUint — код идентичен, отличаются типы)",[14,23,24,25,28],{},"обобщённое программирование = парадигма: пишешь код один раз, компилятор ",[18,26,27],{},"допишет"," для конкретных типов",[14,30,31,34],{},[18,32,33],{},"инстанцирование"," выполняется на этапе компиляции → сохраняется статическая типизация",[14,36,37],{},"до Go 1.18: интерфейсы (теряем типобезопасность), рефлексия, unsafe, кодогенерация",[14,39,40],{},"с Go 1.0 были встроенные обобщённые типы (map, chan, slice) и функции (new, make, len, close)",[42,43],"hr",{},[45,46,48],"h2",{"id":47},"дженерики","Дженерики",[50,51,53],"h3",{"id":52},"зачем-нужны-дженерики","Зачем нужны дженерики",[50,55,57],{"id":56},"проблема-дублирования","Проблема дублирования",[59,60,64],"pre",{"className":61,"code":62,"language":63,"meta":5,"style":5},"language-go shiki shiki-themes github-dark","\u002F\u002F ❌ два раза один и тот же код\nfunc maxInt(a, b int) int {\n    if a > b { return a }\n    return b\n}\n\nfunc maxUint(a, b uint) uint {\n    if a > b { return a }\n    return b\n}\n","go",[65,66,67,76,113,134,143,149,156,182,197,204],"code",{"__ignoreMap":5},[68,69,72],"span",{"class":70,"line":71},"line",1,[68,73,75],{"class":74},"sAwPA","\u002F\u002F ❌ два раза один и тот же код\n",[68,77,79,83,87,91,95,98,101,104,107,110],{"class":70,"line":78},2,[68,80,82],{"class":81},"snl16","func",[68,84,86],{"class":85},"svObZ"," maxInt",[68,88,90],{"class":89},"s95oV","(",[68,92,94],{"class":93},"s9osk","a",[68,96,97],{"class":89},", ",[68,99,100],{"class":93},"b",[68,102,103],{"class":81}," int",[68,105,106],{"class":89},") ",[68,108,109],{"class":81},"int",[68,111,112],{"class":89}," {\n",[68,114,116,119,122,125,128,131],{"class":70,"line":115},3,[68,117,118],{"class":81},"    if",[68,120,121],{"class":89}," a ",[68,123,124],{"class":81},">",[68,126,127],{"class":89}," b { ",[68,129,130],{"class":81},"return",[68,132,133],{"class":89}," a }\n",[68,135,137,140],{"class":70,"line":136},4,[68,138,139],{"class":81},"    return",[68,141,142],{"class":89}," b\n",[68,144,146],{"class":70,"line":145},5,[68,147,148],{"class":89},"}\n",[68,150,152],{"class":70,"line":151},6,[68,153,155],{"emptyLinePlaceholder":154},true,"\n",[68,157,159,161,164,166,168,170,172,175,177,180],{"class":70,"line":158},7,[68,160,82],{"class":81},[68,162,163],{"class":85}," maxUint",[68,165,90],{"class":89},[68,167,94],{"class":93},[68,169,97],{"class":89},[68,171,100],{"class":93},[68,173,174],{"class":81}," uint",[68,176,106],{"class":89},[68,178,179],{"class":81},"uint",[68,181,112],{"class":89},[68,183,185,187,189,191,193,195],{"class":70,"line":184},8,[68,186,118],{"class":81},[68,188,121],{"class":89},[68,190,124],{"class":81},[68,192,127],{"class":89},[68,194,130],{"class":81},[68,196,133],{"class":89},[68,198,200,202],{"class":70,"line":199},9,[68,201,139],{"class":81},[68,203,142],{"class":89},[68,205,207],{"class":70,"line":206},10,[68,208,148],{"class":89},[50,210,212],{"id":211},"с-дженериками-go-118","С дженериками (Go 1.18+)",[59,214,216],{"className":61,"code":215,"language":63,"meta":5,"style":5},"\u002F\u002F ✅ один раз\nfunc max[T int | uint](a, b T) T {\n    if a > b { return a }\n    return b\n}\n\nmax[int](1, 2)    \u002F\u002F явное инстанцирование\nmax(uint(1), 2)   \u002F\u002F компилятор выведет тип сам\n",[65,217,218,223,261,275,281,285,289,315],{"__ignoreMap":5},[68,219,220],{"class":70,"line":71},[68,221,222],{"class":74},"\u002F\u002F ✅ один раз\n",[68,224,225,227,230,233,236,238,241,243,246,248,250,252,255,257,259],{"class":70,"line":78},[68,226,82],{"class":81},[68,228,229],{"class":85}," max",[68,231,232],{"class":89},"[",[68,234,235],{"class":93},"T",[68,237,103],{"class":81},[68,239,240],{"class":81}," |",[68,242,174],{"class":81},[68,244,245],{"class":89},"](",[68,247,94],{"class":93},[68,249,97],{"class":89},[68,251,100],{"class":93},[68,253,254],{"class":85}," T",[68,256,106],{"class":89},[68,258,235],{"class":85},[68,260,112],{"class":89},[68,262,263,265,267,269,271,273],{"class":70,"line":115},[68,264,118],{"class":81},[68,266,121],{"class":89},[68,268,124],{"class":81},[68,270,127],{"class":89},[68,272,130],{"class":81},[68,274,133],{"class":89},[68,276,277,279],{"class":70,"line":136},[68,278,139],{"class":81},[68,280,142],{"class":89},[68,282,283],{"class":70,"line":145},[68,284,148],{"class":89},[68,286,287],{"class":70,"line":151},[68,288,155],{"emptyLinePlaceholder":154},[68,290,291,294,296,298,300,304,306,309,312],{"class":70,"line":158},[68,292,293],{"class":85},"max",[68,295,232],{"class":89},[68,297,109],{"class":81},[68,299,245],{"class":89},[68,301,303],{"class":302},"sDLfK","1",[68,305,97],{"class":89},[68,307,308],{"class":302},"2",[68,310,311],{"class":89},")    ",[68,313,314],{"class":74},"\u002F\u002F явное инстанцирование\n",[68,316,317,319,321,323,325,327,330,332,335],{"class":70,"line":184},[68,318,293],{"class":85},[68,320,90],{"class":89},[68,322,179],{"class":81},[68,324,90],{"class":89},[68,326,303],{"class":302},[68,328,329],{"class":89},"), ",[68,331,308],{"class":302},[68,333,334],{"class":89},")   ",[68,336,337],{"class":74},"\u002F\u002F компилятор выведет тип сам\n",[339,340,341],"p",{},"Компилятор возьмёт обобщённый код и сгенерирует реализации для int и uint. Вы этот код не пишете — его пишет компилятор.",[50,343,345],{"id":344},"до-118-как-жили-без-дженериков","До 1.18 — как жили без дженериков",[59,347,349],{"className":61,"code":348,"language":63,"meta":5,"style":5},"\u002F\u002F Пустой интерфейс — теряем типобезопасность\nfunc maxAny(a, b any) any { ... }  \u002F\u002F что вернётся? кто проверит типы?\n\n\u002F\u002F Кодогенерация — громоздко\n\u002F\u002Fgo:generate ...\n",[65,350,351,356,391,395,400],{"__ignoreMap":5},[68,352,353],{"class":70,"line":71},[68,354,355],{"class":74},"\u002F\u002F Пустой интерфейс — теряем типобезопасность\n",[68,357,358,360,363,365,367,369,371,374,376,379,382,385,388],{"class":70,"line":78},[68,359,82],{"class":81},[68,361,362],{"class":85}," maxAny",[68,364,90],{"class":89},[68,366,94],{"class":93},[68,368,97],{"class":89},[68,370,100],{"class":93},[68,372,373],{"class":85}," any",[68,375,106],{"class":89},[68,377,378],{"class":85},"any",[68,380,381],{"class":89}," { ",[68,383,384],{"class":81},"...",[68,386,387],{"class":89}," }  ",[68,389,390],{"class":74},"\u002F\u002F что вернётся? кто проверит типы?\n",[68,392,393],{"class":70,"line":115},[68,394,155],{"emptyLinePlaceholder":154},[68,396,397],{"class":70,"line":136},[68,398,399],{"class":74},"\u002F\u002F Кодогенерация — громоздко\n",[68,401,402],{"class":70,"line":145},[68,403,404],{"class":74},"\u002F\u002Fgo:generate ...\n",[339,406,407],{},"88% респондентов опроса назвали отсутствие дженериков критической проблемой.",[339,409,410],{},"18% не использовали Go именно из-за отсутствия дженериков.",[42,412],{},[11,414,415,422,437,447,457],{},[14,416,417,418,421],{},"constraint = ",[18,419,420],{},"интерфейс",", ограничивающий допустимые типы для generic-параметра",[14,423,424,425,428,429,432,433,436],{},"типы через ",[65,426,427],{},"|"," на одной строке = ",[18,430,431],{},"OR"," (один из); на новых строках = ",[18,434,435],{},"AND"," (все условия)",[14,438,439,442,443,446],{},[65,440,441],{},"~int"," (тильда) = int ",[18,444,445],{},"и все type definitions"," с базовым типом int",[14,448,449,450,453,454,456],{},"зарезервированные: ",[65,451,452],{},"comparable"," (==, !=), ",[65,455,378],{}," (любой тип)",[14,458,459,460,97,463,97,466,469,470,473],{},"экспериментальные: ",[65,461,462],{},"constraints.Ordered",[65,464,465],{},"constraints.Integer",[65,467,468],{},"constraints.Float"," (пакет ",[65,471,472],{},"golang.org\u002Fx\u002Fexp\u002Fconstraints",")",[42,475],{},[50,477,479],{"id":478},"constraints-и-type-sets","Constraints и type sets",[50,481,483],{"id":482},"or-типы-на-одной-строке","OR — типы на одной строке",[59,485,487],{"className":61,"code":486,"language":63,"meta":5,"style":5},"type Number interface {\n    int | float64 | uint  \u002F\u002F ИЛИ: один из этих типов\n}\n",[65,488,489,502,519],{"__ignoreMap":5},[68,490,491,494,497,500],{"class":70,"line":71},[68,492,493],{"class":81},"type",[68,495,496],{"class":85}," Number",[68,498,499],{"class":81}," interface",[68,501,112],{"class":89},[68,503,504,507,509,512,514,516],{"class":70,"line":78},[68,505,506],{"class":81},"    int",[68,508,240],{"class":81},[68,510,511],{"class":81}," float64",[68,513,240],{"class":81},[68,515,174],{"class":81},[68,517,518],{"class":74},"  \u002F\u002F ИЛИ: один из этих типов\n",[68,520,521],{"class":70,"line":115},[68,522,148],{"class":89},[339,524,525,526,528,529,532],{},"Типы через ",[65,527,427],{}," на одной строке означают, что тип должен быть ",[18,530,531],{},"одним из"," перечисленных.",[50,534,536],{"id":535},"and-условия-на-разных-строках","AND — условия на разных строках",[59,538,540],{"className":61,"code":539,"language":63,"meta":5,"style":5},"type MyConstraint interface {\n    ~int | ~float64       \u002F\u002F базовый тип int или float64\n    String() string       \u002F\u002F И у типа должен быть метод String()\n    fmt.Stringer          \u002F\u002F И должен реализовывать Stringer\n}\n",[65,541,542,553,566,580,594],{"__ignoreMap":5},[68,543,544,546,549,551],{"class":70,"line":71},[68,545,493],{"class":81},[68,547,548],{"class":85}," MyConstraint",[68,550,499],{"class":81},[68,552,112],{"class":89},[68,554,555,558,560,563],{"class":70,"line":78},[68,556,557],{"class":81},"    ~int",[68,559,240],{"class":81},[68,561,562],{"class":81}," ~float64",[68,564,565],{"class":74},"       \u002F\u002F базовый тип int или float64\n",[68,567,568,571,574,577],{"class":70,"line":115},[68,569,570],{"class":85},"    String",[68,572,573],{"class":89},"() ",[68,575,576],{"class":81},"string",[68,578,579],{"class":74},"       \u002F\u002F И у типа должен быть метод String()\n",[68,581,582,585,588,591],{"class":70,"line":136},[68,583,584],{"class":85},"    fmt",[68,586,587],{"class":89},".",[68,589,590],{"class":85},"Stringer",[68,592,593],{"class":74},"          \u002F\u002F И должен реализовывать Stringer\n",[68,595,596],{"class":70,"line":145},[68,597,148],{"class":89},[339,599,600,601,587],{},"Каждая строка — отдельное условие. Тип должен удовлетворять ",[18,602,603],{},"всем",[50,605,607],{"id":606},"тильда-базовый-тип","Тильда — базовый тип",[59,609,611],{"className":61,"code":610,"language":63,"meta":5,"style":5},"type Integer1 interface { int | int8 | int16 }     \u002F\u002F только эти типы\ntype Integer2 interface { ~int | ~int8 | ~int16 }   \u002F\u002F + type definitions\n\ntype MyInt int  \u002F\u002F базовый тип = int\n\nfunc process1[T Integer1](v T) {}\nfunc process2[T Integer2](v T) {}\n\nprocess1(MyInt(1))  \u002F\u002F ❌ MyInt ≠ int\nprocess2(MyInt(1))  \u002F\u002F ✅ базовый тип MyInt = int\n",[65,612,613,642,671,675,687,691,714,735,739,759],{"__ignoreMap":5},[68,614,615,617,620,622,624,626,628,631,633,636,639],{"class":70,"line":71},[68,616,493],{"class":81},[68,618,619],{"class":85}," Integer1",[68,621,499],{"class":81},[68,623,381],{"class":89},[68,625,109],{"class":81},[68,627,240],{"class":81},[68,629,630],{"class":81}," int8",[68,632,240],{"class":81},[68,634,635],{"class":81}," int16",[68,637,638],{"class":89}," }     ",[68,640,641],{"class":74},"\u002F\u002F только эти типы\n",[68,643,644,646,649,651,653,655,657,660,662,665,668],{"class":70,"line":78},[68,645,493],{"class":81},[68,647,648],{"class":85}," Integer2",[68,650,499],{"class":81},[68,652,381],{"class":89},[68,654,441],{"class":81},[68,656,240],{"class":81},[68,658,659],{"class":81}," ~int8",[68,661,240],{"class":81},[68,663,664],{"class":81}," ~int16",[68,666,667],{"class":89}," }   ",[68,669,670],{"class":74},"\u002F\u002F + type definitions\n",[68,672,673],{"class":70,"line":115},[68,674,155],{"emptyLinePlaceholder":154},[68,676,677,679,682,684],{"class":70,"line":136},[68,678,493],{"class":81},[68,680,681],{"class":85}," MyInt",[68,683,103],{"class":81},[68,685,686],{"class":74},"  \u002F\u002F базовый тип = int\n",[68,688,689],{"class":70,"line":145},[68,690,155],{"emptyLinePlaceholder":154},[68,692,693,695,698,700,702,704,706,709,711],{"class":70,"line":151},[68,694,82],{"class":81},[68,696,697],{"class":85}," process1",[68,699,232],{"class":89},[68,701,235],{"class":93},[68,703,619],{"class":85},[68,705,245],{"class":89},[68,707,708],{"class":93},"v",[68,710,254],{"class":85},[68,712,713],{"class":89},") {}\n",[68,715,716,718,721,723,725,727,729,731,733],{"class":70,"line":158},[68,717,82],{"class":81},[68,719,720],{"class":85}," process2",[68,722,232],{"class":89},[68,724,235],{"class":93},[68,726,648],{"class":85},[68,728,245],{"class":89},[68,730,708],{"class":93},[68,732,254],{"class":85},[68,734,713],{"class":89},[68,736,737],{"class":70,"line":184},[68,738,155],{"emptyLinePlaceholder":154},[68,740,741,744,746,749,751,753,756],{"class":70,"line":199},[68,742,743],{"class":85},"process1",[68,745,90],{"class":89},[68,747,748],{"class":85},"MyInt",[68,750,90],{"class":89},[68,752,303],{"class":302},[68,754,755],{"class":89},"))  ",[68,757,758],{"class":74},"\u002F\u002F ❌ MyInt ≠ int\n",[68,760,761,764,766,768,770,772,774],{"class":70,"line":206},[68,762,763],{"class":85},"process2",[68,765,90],{"class":89},[68,767,748],{"class":85},[68,769,90],{"class":89},[68,771,303],{"class":302},[68,773,755],{"class":89},[68,775,776],{"class":74},"\u002F\u002F ✅ базовый тип MyInt = int\n",[339,778,779],{},"Без тильды принимаются только точные типы. С тильдой — также любой named type поверх базового.",[50,781,783],{"id":782},"анонимные-constraints-inline","Анонимные constraints (inline)",[59,785,787],{"className":61,"code":786,"language":63,"meta":5,"style":5},"\u002F\u002F Именованный constraint\nfunc sum[T Number](a, b T) T { return a + b }\n\n\u002F\u002F Анонимный — прямо в сигнатуре\nfunc sum[T interface{ int | float64 }](a, b T) T { return a + b }\n\n\u002F\u002F Сокращённая форма (без interface{})\nfunc sum[T int | float64](a, b T) T { return a + b }\n",[65,788,789,794,833,837,842,888,892,897],{"__ignoreMap":5},[68,790,791],{"class":70,"line":71},[68,792,793],{"class":74},"\u002F\u002F Именованный constraint\n",[68,795,796,798,801,803,805,807,809,811,813,815,817,819,821,823,825,827,830],{"class":70,"line":78},[68,797,82],{"class":81},[68,799,800],{"class":85}," sum",[68,802,232],{"class":89},[68,804,235],{"class":93},[68,806,496],{"class":85},[68,808,245],{"class":89},[68,810,94],{"class":93},[68,812,97],{"class":89},[68,814,100],{"class":93},[68,816,254],{"class":85},[68,818,106],{"class":89},[68,820,235],{"class":85},[68,822,381],{"class":89},[68,824,130],{"class":81},[68,826,121],{"class":89},[68,828,829],{"class":81},"+",[68,831,832],{"class":89}," b }\n",[68,834,835],{"class":70,"line":115},[68,836,155],{"emptyLinePlaceholder":154},[68,838,839],{"class":70,"line":136},[68,840,841],{"class":74},"\u002F\u002F Анонимный — прямо в сигнатуре\n",[68,843,844,846,848,850,852,854,857,859,861,863,866,868,870,872,874,876,878,880,882,884,886],{"class":70,"line":145},[68,845,82],{"class":81},[68,847,800],{"class":85},[68,849,232],{"class":89},[68,851,235],{"class":93},[68,853,499],{"class":81},[68,855,856],{"class":89},"{ ",[68,858,109],{"class":81},[68,860,240],{"class":81},[68,862,511],{"class":81},[68,864,865],{"class":89}," }](",[68,867,94],{"class":93},[68,869,97],{"class":89},[68,871,100],{"class":93},[68,873,254],{"class":85},[68,875,106],{"class":89},[68,877,235],{"class":85},[68,879,381],{"class":89},[68,881,130],{"class":81},[68,883,121],{"class":89},[68,885,829],{"class":81},[68,887,832],{"class":89},[68,889,890],{"class":70,"line":151},[68,891,155],{"emptyLinePlaceholder":154},[68,893,894],{"class":70,"line":158},[68,895,896],{"class":74},"\u002F\u002F Сокращённая форма (без interface{})\n",[68,898,899,901,903,905,907,909,911,913,915,917,919,921,923,925,927,929,931,933,935],{"class":70,"line":184},[68,900,82],{"class":81},[68,902,800],{"class":85},[68,904,232],{"class":89},[68,906,235],{"class":93},[68,908,103],{"class":81},[68,910,240],{"class":81},[68,912,511],{"class":81},[68,914,245],{"class":89},[68,916,94],{"class":93},[68,918,97],{"class":89},[68,920,100],{"class":93},[68,922,254],{"class":85},[68,924,106],{"class":89},[68,926,235],{"class":85},[68,928,381],{"class":89},[68,930,130],{"class":81},[68,932,121],{"class":89},[68,934,829],{"class":81},[68,936,832],{"class":89},[339,938,939],{},"Inline constraint удобен для одноразовых ограничений; именованный — если переиспользуется.",[50,941,943],{"id":942},"comparable-и-any","comparable и any",[59,945,947],{"className":61,"code":946,"language":63,"meta":5,"style":5},"func getKeys[K comparable, V any](m map[K]V) []K { ... }\n\u002F\u002F K — можно ==, != (ключи map)\n\u002F\u002F V — абсолютно любой тип\n",[65,948,949,1000,1005],{"__ignoreMap":5},[68,950,951,953,956,958,961,964,966,969,971,973,976,979,981,983,986,988,991,993,995,997],{"class":70,"line":71},[68,952,82],{"class":81},[68,954,955],{"class":85}," getKeys",[68,957,232],{"class":89},[68,959,960],{"class":93},"K",[68,962,963],{"class":85}," comparable",[68,965,97],{"class":89},[68,967,968],{"class":93},"V",[68,970,373],{"class":85},[68,972,245],{"class":89},[68,974,975],{"class":93},"m",[68,977,978],{"class":81}," map",[68,980,232],{"class":89},[68,982,960],{"class":85},[68,984,985],{"class":89},"]",[68,987,968],{"class":85},[68,989,990],{"class":89},") []",[68,992,960],{"class":85},[68,994,381],{"class":89},[68,996,384],{"class":81},[68,998,999],{"class":89}," }\n",[68,1001,1002],{"class":70,"line":78},[68,1003,1004],{"class":74},"\u002F\u002F K — можно ==, != (ключи map)\n",[68,1006,1007],{"class":70,"line":115},[68,1008,1009],{"class":74},"\u002F\u002F V — абсолютно любой тип\n",[339,1011,1012,1014,1015,1018,1019,1022],{},[65,1013,452],{}," — встроенный constraint: типы, поддерживающие ",[65,1016,1017],{},"=="," и ",[65,1020,1021],{},"!=",". Нужен для ключей map и операций сравнения.",[339,1024,1025,1027,1028,1031],{},[65,1026,378],{}," — алиас для ",[65,1029,1030],{},"interface{}",", принимает абсолютно любой тип.",[42,1033],{},[11,1035,1036,1042,1049,1056,1067],{},[14,1037,1038,1041],{},[18,1039,1040],{},"type inference"," — компилятор выводит типы из аргументов функции, не нужно указывать явно",[14,1043,1044,1045,1048],{},"для ",[18,1046,1047],{},"структур"," не работает — всегда явно инстанцировать",[14,1050,1051,1052,1055],{},"если ",[18,1053,1054],{},"нечего вывести"," (нет аргументов с generic-типом) — явно указывать",[14,1057,1058,1059,1062,1063,1066],{},"можно ",[18,1060,1061],{},"пропускать"," типы-параметры только ",[18,1064,1065],{},"с начала"," (префикс), не из середины",[14,1068,1069],{},"типы-параметры (объявление) vs типы-аргументы (вызов) — аналогия с параметрами\u002Fаргументами функций",[42,1071],{},[50,1073,1075],{"id":1074},"вывод-типов","Вывод типов",[50,1077,1079],{"id":1078},"type-inference-работает","Type inference работает",[59,1081,1083],{"className":61,"code":1082,"language":63,"meta":5,"style":5},"func print[T any](v T) { \u002F* вывод v *\u002F }\n\nprint[int](100)    \u002F\u002F явно\nprint(100)          \u002F\u002F ✅ компилятор выведет int из аргумента\nprint(\"hello\")      \u002F\u002F ✅ выведет string\n",[65,1084,1085,1112,1116,1135,1149],{"__ignoreMap":5},[68,1086,1087,1089,1092,1094,1096,1098,1100,1102,1104,1107,1110],{"class":70,"line":71},[68,1088,82],{"class":81},[68,1090,1091],{"class":85}," print",[68,1093,232],{"class":89},[68,1095,235],{"class":93},[68,1097,373],{"class":85},[68,1099,245],{"class":89},[68,1101,708],{"class":93},[68,1103,254],{"class":85},[68,1105,1106],{"class":89},") { ",[68,1108,1109],{"class":74},"\u002F* вывод v *\u002F",[68,1111,999],{"class":89},[68,1113,1114],{"class":70,"line":78},[68,1115,155],{"emptyLinePlaceholder":154},[68,1117,1118,1121,1123,1125,1127,1130,1132],{"class":70,"line":115},[68,1119,1120],{"class":85},"print",[68,1122,232],{"class":89},[68,1124,109],{"class":81},[68,1126,245],{"class":89},[68,1128,1129],{"class":302},"100",[68,1131,311],{"class":89},[68,1133,1134],{"class":74},"\u002F\u002F явно\n",[68,1136,1137,1139,1141,1143,1146],{"class":70,"line":136},[68,1138,1120],{"class":85},[68,1140,90],{"class":89},[68,1142,1129],{"class":302},[68,1144,1145],{"class":89},")          ",[68,1147,1148],{"class":74},"\u002F\u002F ✅ компилятор выведет int из аргумента\n",[68,1150,1151,1153,1155,1159,1162],{"class":70,"line":145},[68,1152,1120],{"class":85},[68,1154,90],{"class":89},[68,1156,1158],{"class":1157},"sU2Wk","\"hello\"",[68,1160,1161],{"class":89},")      ",[68,1163,1164],{"class":74},"\u002F\u002F ✅ выведет string\n",[50,1166,1168],{"id":1167},"не-работает-нет-аргументов","Не работает: нет аргументов",[59,1170,1172],{"className":61,"code":1171,"language":63,"meta":5,"style":5},"func create[T any]() *T {\n    var v T\n    return &v\n}\n\ncreate()        \u002F\u002F ❌ компилятору нечего вывести\ncreate[int]()   \u002F\u002F ✅ явно\n\n\u002F\u002F Даже если слева очевидный тип:\nvar p *int = create()  \u002F\u002F ❌ всё равно не выводит\n",[65,1173,1174,1197,1208,1218,1222,1226,1237,1251,1255,1260],{"__ignoreMap":5},[68,1175,1176,1178,1181,1183,1185,1187,1190,1193,1195],{"class":70,"line":71},[68,1177,82],{"class":81},[68,1179,1180],{"class":85}," create",[68,1182,232],{"class":89},[68,1184,235],{"class":93},[68,1186,373],{"class":85},[68,1188,1189],{"class":89},"]() ",[68,1191,1192],{"class":81},"*",[68,1194,235],{"class":85},[68,1196,112],{"class":89},[68,1198,1199,1202,1205],{"class":70,"line":78},[68,1200,1201],{"class":81},"    var",[68,1203,1204],{"class":89}," v ",[68,1206,1207],{"class":85},"T\n",[68,1209,1210,1212,1215],{"class":70,"line":115},[68,1211,139],{"class":81},[68,1213,1214],{"class":81}," &",[68,1216,1217],{"class":89},"v\n",[68,1219,1220],{"class":70,"line":136},[68,1221,148],{"class":89},[68,1223,1224],{"class":70,"line":145},[68,1225,155],{"emptyLinePlaceholder":154},[68,1227,1228,1231,1234],{"class":70,"line":151},[68,1229,1230],{"class":85},"create",[68,1232,1233],{"class":89},"()        ",[68,1235,1236],{"class":74},"\u002F\u002F ❌ компилятору нечего вывести\n",[68,1238,1239,1241,1243,1245,1248],{"class":70,"line":158},[68,1240,1230],{"class":85},[68,1242,232],{"class":89},[68,1244,109],{"class":81},[68,1246,1247],{"class":89},"]()   ",[68,1249,1250],{"class":74},"\u002F\u002F ✅ явно\n",[68,1252,1253],{"class":70,"line":184},[68,1254,155],{"emptyLinePlaceholder":154},[68,1256,1257],{"class":70,"line":199},[68,1258,1259],{"class":74},"\u002F\u002F Даже если слева очевидный тип:\n",[68,1261,1262,1265,1268,1271,1274,1276,1279],{"class":70,"line":206},[68,1263,1264],{"class":81},"var",[68,1266,1267],{"class":89}," p ",[68,1269,1270],{"class":81},"*int",[68,1272,1273],{"class":81}," =",[68,1275,1180],{"class":85},[68,1277,1278],{"class":89},"()  ",[68,1280,1281],{"class":74},"\u002F\u002F ❌ всё равно не выводит\n",[339,1283,1284],{},"Go не выводит тип из контекста присваивания — только из аргументов вызова.",[50,1286,1288],{"id":1287},"не-работает-структуры","Не работает: структуры",[59,1290,1292],{"className":61,"code":1291,"language":63,"meta":5,"style":5},"type Box[T any] struct { Value T }\n\nBox{Value: 42}       \u002F\u002F ❌ не компилируется\nBox[int]{Value: 42}  \u002F\u002F ✅ всегда явно для структур\n",[65,1293,1294,1320,1324,1341],{"__ignoreMap":5},[68,1295,1296,1298,1301,1303,1305,1307,1310,1313,1316,1318],{"class":70,"line":71},[68,1297,493],{"class":81},[68,1299,1300],{"class":85}," Box",[68,1302,232],{"class":89},[68,1304,235],{"class":93},[68,1306,373],{"class":85},[68,1308,1309],{"class":89},"] ",[68,1311,1312],{"class":81},"struct",[68,1314,1315],{"class":89}," { Value ",[68,1317,235],{"class":85},[68,1319,999],{"class":89},[68,1321,1322],{"class":70,"line":78},[68,1323,155],{"emptyLinePlaceholder":154},[68,1325,1326,1329,1332,1335,1338],{"class":70,"line":115},[68,1327,1328],{"class":85},"Box",[68,1330,1331],{"class":89},"{Value: ",[68,1333,1334],{"class":302},"42",[68,1336,1337],{"class":89},"}       ",[68,1339,1340],{"class":74},"\u002F\u002F ❌ не компилируется\n",[68,1342,1343,1345,1347,1349,1352,1354,1357],{"class":70,"line":136},[68,1344,1328],{"class":85},[68,1346,232],{"class":89},[68,1348,109],{"class":81},[68,1350,1351],{"class":89},"]{Value: ",[68,1353,1334],{"class":302},[68,1355,1356],{"class":89},"}  ",[68,1358,1359],{"class":74},"\u002F\u002F ✅ всегда явно для структур\n",[339,1361,1362],{},"Даже когда по полю очевидно, компилятор не догадывается.",[50,1364,1366],{"id":1365},"пропуск-типов-только-с-начала","Пропуск типов — только с начала",[59,1368,1370],{"className":61,"code":1369,"language":63,"meta":5,"style":5},"func process1[T comparable, K any, E int](a T, b K) E { ... }\n\u002F\u002F T и K выводятся из аргументов, E — нет\nprocess1[int](\"hello\", 3.14)  \u002F\u002F ❌ int подставится в T, не в E\n\nfunc process2[E int, T comparable, K any](a T, b K) E { ... }\n\u002F\u002F E первый — указываем явно, T и K выведутся\nprocess2[int](\"hello\", 3.14)  \u002F\u002F ✅ E=int, T=string, K=float64\n",[65,1371,1372,1420,1425,1448,1452,1498,1503],{"__ignoreMap":5},[68,1373,1374,1376,1378,1380,1382,1384,1386,1388,1390,1392,1395,1397,1399,1401,1403,1405,1407,1410,1412,1414,1416,1418],{"class":70,"line":71},[68,1375,82],{"class":81},[68,1377,697],{"class":85},[68,1379,232],{"class":89},[68,1381,235],{"class":93},[68,1383,963],{"class":85},[68,1385,97],{"class":89},[68,1387,960],{"class":93},[68,1389,373],{"class":85},[68,1391,97],{"class":89},[68,1393,1394],{"class":93},"E",[68,1396,103],{"class":81},[68,1398,245],{"class":89},[68,1400,94],{"class":93},[68,1402,254],{"class":85},[68,1404,97],{"class":89},[68,1406,100],{"class":93},[68,1408,1409],{"class":85}," K",[68,1411,106],{"class":89},[68,1413,1394],{"class":85},[68,1415,381],{"class":89},[68,1417,384],{"class":81},[68,1419,999],{"class":89},[68,1421,1422],{"class":70,"line":78},[68,1423,1424],{"class":74},"\u002F\u002F T и K выводятся из аргументов, E — нет\n",[68,1426,1427,1429,1431,1433,1435,1437,1439,1442,1445],{"class":70,"line":115},[68,1428,743],{"class":85},[68,1430,232],{"class":89},[68,1432,109],{"class":81},[68,1434,245],{"class":89},[68,1436,1158],{"class":1157},[68,1438,97],{"class":89},[68,1440,1441],{"class":302},"3.14",[68,1443,1444],{"class":89},")  ",[68,1446,1447],{"class":74},"\u002F\u002F ❌ int подставится в T, не в E\n",[68,1449,1450],{"class":70,"line":136},[68,1451,155],{"emptyLinePlaceholder":154},[68,1453,1454,1456,1458,1460,1462,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1484,1486,1488,1490,1492,1494,1496],{"class":70,"line":145},[68,1455,82],{"class":81},[68,1457,720],{"class":85},[68,1459,232],{"class":89},[68,1461,1394],{"class":93},[68,1463,103],{"class":81},[68,1465,97],{"class":89},[68,1467,235],{"class":93},[68,1469,963],{"class":85},[68,1471,97],{"class":89},[68,1473,960],{"class":93},[68,1475,373],{"class":85},[68,1477,245],{"class":89},[68,1479,94],{"class":93},[68,1481,254],{"class":85},[68,1483,97],{"class":89},[68,1485,100],{"class":93},[68,1487,1409],{"class":85},[68,1489,106],{"class":89},[68,1491,1394],{"class":85},[68,1493,381],{"class":89},[68,1495,384],{"class":81},[68,1497,999],{"class":89},[68,1499,1500],{"class":70,"line":151},[68,1501,1502],{"class":74},"\u002F\u002F E первый — указываем явно, T и K выведутся\n",[68,1504,1505,1507,1509,1511,1513,1515,1517,1519,1521],{"class":70,"line":158},[68,1506,763],{"class":85},[68,1508,232],{"class":89},[68,1510,109],{"class":81},[68,1512,245],{"class":89},[68,1514,1158],{"class":1157},[68,1516,97],{"class":89},[68,1518,1441],{"class":302},[68,1520,1444],{"class":89},[68,1522,1523],{"class":74},"\u002F\u002F ✅ E=int, T=string, K=float64\n",[339,1525,1526,1527,1530,1531,1533],{},"Правило: явно указать можно только ",[18,1528,1529],{},"префикс"," type arguments. Пропущенный справа суффикс компилятор может вывести из обычных аргументов функции. Указать только ",[65,1532,1394],{},", если он стоит третьим, нельзя — поэтому параметры, которые не выводятся, обычно ставят первыми.",[42,1535],{},[11,1537,1538,1544,1550,1555,1560,1573],{},[14,1539,1540,1543],{},[18,1541,1542],{},"нет обобщённых методов"," — хак: функция с явным ресивером",[14,1545,1546,1549],{},[18,1547,1548],{},"нельзя"," создать константу из generic-типа",[14,1551,1552,1554],{},[18,1553,1548],{}," передавать числа как параметры типов (в отличие от C++)",[14,1556,1557,1559],{},[18,1558,1548],{}," встроить type parameter как анонимное поле",[14,1561,1562,1563,97,1566,1569,1570,1572],{},"проблемы с ",[18,1564,1565],{},"указателями",[18,1567,1568],{},"map+slice"," нельзя объединить, string+",[68,1571],{},"byte — только чтение",[14,1574,1575,1576,1579],{},"метод, объявленный на типе, но ",[18,1577,1578],{},"не в constraint"," — недоступен",[42,1581],{},[50,1583,1585],{"id":1584},"ограничения-дженериков","Ограничения дженериков",[50,1587,1589],{"id":1588},"нет-обобщённых-методов","Нет обобщённых методов",[59,1591,1593],{"className":61,"code":1592,"language":63,"meta":5,"style":5},"type MyStruct struct{}\n\n\u002F\u002F ❌ нельзя\nfunc (s *MyStruct) Process[T any](v T) {}\n\n\u002F\u002F ✅ хак: обобщённая функция с явным ресивером\nfunc Process[T any](s *MyStruct, v T) {\n    _ = v \u002F\u002F логика здесь\n}\n",[65,1594,1595,1608,1612,1617,1651,1655,1660,1692,1705],{"__ignoreMap":5},[68,1596,1597,1599,1602,1605],{"class":70,"line":71},[68,1598,493],{"class":81},[68,1600,1601],{"class":85}," MyStruct",[68,1603,1604],{"class":81}," struct",[68,1606,1607],{"class":89},"{}\n",[68,1609,1610],{"class":70,"line":78},[68,1611,155],{"emptyLinePlaceholder":154},[68,1613,1614],{"class":70,"line":115},[68,1615,1616],{"class":74},"\u002F\u002F ❌ нельзя\n",[68,1618,1619,1621,1624,1627,1629,1632,1634,1637,1639,1641,1643,1645,1647,1649],{"class":70,"line":136},[68,1620,82],{"class":81},[68,1622,1623],{"class":89}," (",[68,1625,1626],{"class":93},"s ",[68,1628,1192],{"class":81},[68,1630,1631],{"class":85},"MyStruct",[68,1633,106],{"class":89},[68,1635,1636],{"class":85},"Process",[68,1638,232],{"class":89},[68,1640,235],{"class":93},[68,1642,373],{"class":85},[68,1644,245],{"class":89},[68,1646,708],{"class":93},[68,1648,254],{"class":85},[68,1650,713],{"class":89},[68,1652,1653],{"class":70,"line":145},[68,1654,155],{"emptyLinePlaceholder":154},[68,1656,1657],{"class":70,"line":151},[68,1658,1659],{"class":74},"\u002F\u002F ✅ хак: обобщённая функция с явным ресивером\n",[68,1661,1662,1664,1667,1669,1671,1673,1675,1678,1681,1683,1685,1687,1689],{"class":70,"line":158},[68,1663,82],{"class":81},[68,1665,1666],{"class":85}," Process",[68,1668,232],{"class":89},[68,1670,235],{"class":93},[68,1672,373],{"class":85},[68,1674,245],{"class":89},[68,1676,1677],{"class":93},"s",[68,1679,1680],{"class":81}," *",[68,1682,1631],{"class":85},[68,1684,97],{"class":89},[68,1686,708],{"class":93},[68,1688,254],{"class":85},[68,1690,1691],{"class":89},") {\n",[68,1693,1694,1697,1700,1702],{"class":70,"line":184},[68,1695,1696],{"class":89},"    _ ",[68,1698,1699],{"class":81},"=",[68,1701,1204],{"class":89},[68,1703,1704],{"class":74},"\u002F\u002F логика здесь\n",[68,1706,1707],{"class":70,"line":199},[68,1708,148],{"class":89},[339,1710,1711],{},"Go не позволяет объявить метод с собственными type-параметрами. Единственный обходной путь — вынести логику в обычную функцию с явным параметром-ресивером.",[50,1713,1715],{"id":1714},"нельзя-создать-константу","Нельзя создать константу",[59,1717,1719],{"className":61,"code":1718,"language":63,"meta":5,"style":5},"func process[T int](v T) {\n    var x T = 0     \u002F\u002F ✅ переменная\n    const c T = 0   \u002F\u002F ❌ даже когда тип один — нельзя\n}\n",[65,1720,1721,1742,1759,1776],{"__ignoreMap":5},[68,1722,1723,1725,1728,1730,1732,1734,1736,1738,1740],{"class":70,"line":71},[68,1724,82],{"class":81},[68,1726,1727],{"class":85}," process",[68,1729,232],{"class":89},[68,1731,235],{"class":93},[68,1733,103],{"class":81},[68,1735,245],{"class":89},[68,1737,708],{"class":93},[68,1739,254],{"class":85},[68,1741,1691],{"class":89},[68,1743,1744,1746,1749,1751,1753,1756],{"class":70,"line":78},[68,1745,1201],{"class":81},[68,1747,1748],{"class":89}," x ",[68,1750,235],{"class":85},[68,1752,1273],{"class":81},[68,1754,1755],{"class":302}," 0",[68,1757,1758],{"class":74},"     \u002F\u002F ✅ переменная\n",[68,1760,1761,1764,1767,1769,1771,1773],{"class":70,"line":115},[68,1762,1763],{"class":81},"    const",[68,1765,1766],{"class":302}," c",[68,1768,254],{"class":85},[68,1770,1273],{"class":81},[68,1772,1755],{"class":302},[68,1774,1775],{"class":74},"   \u002F\u002F ❌ даже когда тип один — нельзя\n",[68,1777,1778],{"class":70,"line":136},[68,1779,148],{"class":89},[339,1781,1782],{},"Константы из generic-типа запрещены даже если constraint ограничивает тип одним конкретным типом.",[50,1784,1786],{"id":1785},"нельзя-передавать-числа-не-типы","Нельзя передавать числа (не типы)",[59,1788,1790],{"className":61,"code":1789,"language":63,"meta":5,"style":5},"\u002F\u002F C++ — можно: template\u003Cint N> struct Array { int data[N]; };\n\u002F\u002F Go — нельзя: параметры только типы\nfunc makeArray[N int]() {}  \u002F\u002F ❌ нет такого синтаксиса\n",[65,1791,1792,1797,1802],{"__ignoreMap":5},[68,1793,1794],{"class":70,"line":71},[68,1795,1796],{"class":74},"\u002F\u002F C++ — можно: template\u003Cint N> struct Array { int data[N]; };\n",[68,1798,1799],{"class":70,"line":78},[68,1800,1801],{"class":74},"\u002F\u002F Go — нельзя: параметры только типы\n",[68,1803,1804,1806,1809,1811,1814,1816,1819],{"class":70,"line":115},[68,1805,82],{"class":81},[68,1807,1808],{"class":85}," makeArray",[68,1810,232],{"class":89},[68,1812,1813],{"class":93},"N",[68,1815,103],{"class":81},[68,1817,1818],{"class":89},"]() {}  ",[68,1820,1821],{"class":74},"\u002F\u002F ❌ нет такого синтаксиса\n",[339,1823,1824],{},"В Go параметры типов — только типы. Передать числовое значение как type-параметр (как в C++ NTTP) невозможно.",[50,1826,1828],{"id":1827},"нельзя-embed-type-parameter","Нельзя embed type parameter",[59,1830,1832],{"className":61,"code":1831,"language":63,"meta":5,"style":5},"type Box[T any] struct {\n    Value T\n}\n\ntype Wrapper[T any] struct {\n    T       \u002F\u002F ❌ нельзя встроить type parameter\n    Box[T]  \u002F\u002F ✅ можно встроить инстанцированный generic-тип\n    Value T \u002F\u002F ✅ обычное поле — работает\n}\n",[65,1833,1834,1852,1859,1863,1867,1886,1894,1909,1918],{"__ignoreMap":5},[68,1835,1836,1838,1840,1842,1844,1846,1848,1850],{"class":70,"line":71},[68,1837,493],{"class":81},[68,1839,1300],{"class":85},[68,1841,232],{"class":89},[68,1843,235],{"class":93},[68,1845,373],{"class":85},[68,1847,1309],{"class":89},[68,1849,1312],{"class":81},[68,1851,112],{"class":89},[68,1853,1854,1857],{"class":70,"line":78},[68,1855,1856],{"class":89},"    Value ",[68,1858,1207],{"class":85},[68,1860,1861],{"class":70,"line":115},[68,1862,148],{"class":89},[68,1864,1865],{"class":70,"line":136},[68,1866,155],{"emptyLinePlaceholder":154},[68,1868,1869,1871,1874,1876,1878,1880,1882,1884],{"class":70,"line":145},[68,1870,493],{"class":81},[68,1872,1873],{"class":85}," Wrapper",[68,1875,232],{"class":89},[68,1877,235],{"class":93},[68,1879,373],{"class":85},[68,1881,1309],{"class":89},[68,1883,1312],{"class":81},[68,1885,112],{"class":89},[68,1887,1888,1891],{"class":70,"line":151},[68,1889,1890],{"class":85},"    T",[68,1892,1893],{"class":74},"       \u002F\u002F ❌ нельзя встроить type parameter\n",[68,1895,1896,1899,1901,1903,1906],{"class":70,"line":158},[68,1897,1898],{"class":85},"    Box",[68,1900,232],{"class":89},[68,1902,235],{"class":85},[68,1904,1905],{"class":89},"]  ",[68,1907,1908],{"class":74},"\u002F\u002F ✅ можно встроить инстанцированный generic-тип\n",[68,1910,1911,1913,1915],{"class":70,"line":184},[68,1912,1856],{"class":89},[68,1914,235],{"class":85},[68,1916,1917],{"class":74}," \u002F\u002F ✅ обычное поле — работает\n",[68,1919,1920],{"class":70,"line":199},[68,1921,148],{"class":89},[339,1923,1924,1925,1927,1928,1931],{},"Запрещено встраивать сам type parameter (",[65,1926,235],{},") как анонимное поле: у него нет фиксированного имени и набора методов. Но инстанцированный generic-тип (",[65,1929,1930],{},"Box[T]",") — обычный именованный тип, его embedding разрешён.",[50,1933,1935],{"id":1934},"проблемы-с-указателями","Проблемы с указателями",[59,1937,1939],{"className":61,"code":1938,"language":63,"meta":5,"style":5},"type PtrConstraint interface { *int32 | *int64 }\nfunc process[T PtrConstraint](v T) {}  \u002F\u002F ✅\n\n\u002F\u002F Но вот так не работает:\ntype NumConstraint interface { int32 | int64 }\nfunc process[T *NumConstraint](v T) {}  \u002F\u002F ❌\n\n\u002F\u002F Обходной путь:\nfunc process[T NumConstraint](v *T) {}  \u002F\u002F ✅\n",[65,1940,1941,1962,1986,1990,1995,2016,2042,2046,2051],{"__ignoreMap":5},[68,1942,1943,1945,1948,1950,1952,1955,1957,1960],{"class":70,"line":71},[68,1944,493],{"class":81},[68,1946,1947],{"class":85}," PtrConstraint",[68,1949,499],{"class":81},[68,1951,381],{"class":89},[68,1953,1954],{"class":81},"*int32",[68,1956,240],{"class":81},[68,1958,1959],{"class":81}," *int64",[68,1961,999],{"class":89},[68,1963,1964,1966,1968,1970,1972,1974,1976,1978,1980,1983],{"class":70,"line":78},[68,1965,82],{"class":81},[68,1967,1727],{"class":85},[68,1969,232],{"class":89},[68,1971,235],{"class":93},[68,1973,1947],{"class":85},[68,1975,245],{"class":89},[68,1977,708],{"class":93},[68,1979,254],{"class":85},[68,1981,1982],{"class":89},") {}  ",[68,1984,1985],{"class":74},"\u002F\u002F ✅\n",[68,1987,1988],{"class":70,"line":115},[68,1989,155],{"emptyLinePlaceholder":154},[68,1991,1992],{"class":70,"line":136},[68,1993,1994],{"class":74},"\u002F\u002F Но вот так не работает:\n",[68,1996,1997,1999,2002,2004,2006,2009,2011,2014],{"class":70,"line":145},[68,1998,493],{"class":81},[68,2000,2001],{"class":85}," NumConstraint",[68,2003,499],{"class":81},[68,2005,381],{"class":89},[68,2007,2008],{"class":81},"int32",[68,2010,240],{"class":81},[68,2012,2013],{"class":81}," int64",[68,2015,999],{"class":89},[68,2017,2018,2020,2022,2024,2026,2028,2031,2033,2035,2037,2039],{"class":70,"line":151},[68,2019,82],{"class":81},[68,2021,1727],{"class":85},[68,2023,232],{"class":89},[68,2025,235],{"class":93},[68,2027,1680],{"class":81},[68,2029,2030],{"class":85},"NumConstraint",[68,2032,245],{"class":89},[68,2034,708],{"class":93},[68,2036,254],{"class":85},[68,2038,1982],{"class":89},[68,2040,2041],{"class":74},"\u002F\u002F ❌\n",[68,2043,2044],{"class":70,"line":158},[68,2045,155],{"emptyLinePlaceholder":154},[68,2047,2048],{"class":70,"line":184},[68,2049,2050],{"class":74},"\u002F\u002F Обходной путь:\n",[68,2052,2053,2055,2057,2059,2061,2063,2065,2067,2069,2071,2073],{"class":70,"line":199},[68,2054,82],{"class":81},[68,2056,1727],{"class":85},[68,2058,232],{"class":89},[68,2060,235],{"class":93},[68,2062,2001],{"class":85},[68,2064,245],{"class":89},[68,2066,708],{"class":93},[68,2068,1680],{"class":81},[68,2070,235],{"class":85},[68,2072,1982],{"class":89},[68,2074,1985],{"class":74},[339,2076,2077,2078,2081,2082,2085,2086,2088],{},"Нельзя использовать ",[65,2079,2080],{},"*InterfaceName"," как constraint. Правильный паттерн: принимать ",[65,2083,2084],{},"*T"," где ",[65,2087,235],{}," ограничен числовым constraint.",[50,2090,2092],{"id":2091},"map-slice-нельзя-объединить","Map + slice — нельзя объединить",[59,2094,2096],{"className":61,"code":2095,"language":63,"meta":5,"style":5},"\u002F\u002F ❌ не компилируется\nfunc get[T map[string]int | []int](v T) int {\n    return v[0]  \u002F\u002F у map и slice разная семантика []\n}\n",[65,2097,2098,2102,2142,2157],{"__ignoreMap":5},[68,2099,2100],{"class":70,"line":71},[68,2101,1340],{"class":74},[68,2103,2104,2106,2109,2111,2113,2115,2117,2119,2121,2123,2125,2128,2130,2132,2134,2136,2138,2140],{"class":70,"line":78},[68,2105,82],{"class":81},[68,2107,2108],{"class":85}," get",[68,2110,232],{"class":89},[68,2112,235],{"class":93},[68,2114,978],{"class":81},[68,2116,232],{"class":89},[68,2118,576],{"class":81},[68,2120,985],{"class":89},[68,2122,109],{"class":81},[68,2124,240],{"class":81},[68,2126,2127],{"class":89}," []",[68,2129,109],{"class":81},[68,2131,245],{"class":89},[68,2133,708],{"class":93},[68,2135,254],{"class":85},[68,2137,106],{"class":89},[68,2139,109],{"class":81},[68,2141,112],{"class":89},[68,2143,2144,2146,2149,2152,2154],{"class":70,"line":115},[68,2145,139],{"class":81},[68,2147,2148],{"class":89}," v[",[68,2150,2151],{"class":302},"0",[68,2153,1905],{"class":89},[68,2155,2156],{"class":74},"\u002F\u002F у map и slice разная семантика []\n",[68,2158,2159],{"class":70,"line":136},[68,2160,148],{"class":89},[339,2162,2163,2164,2167,2168,2171,2172,2175],{},"Причина: map возвращает ",[65,2165,2166],{},"(value, ok)",", slice — только ",[65,2169,2170],{},"value",". Индексация ",[65,2173,2174],{},"[]"," для map и slice несовместима.",[50,2177,2179,2180,1572],{"id":2178},"string-byte-только-чтение","String + ",[68,2181],{},[59,2183,2185],{"className":61,"code":2184,"language":63,"meta":5,"style":5},"func first[T ~string | ~[]byte](v T) byte {\n    return v[0]  \u002F\u002F ✅ читать можно\n}\n\nfunc setFirst[T ~string | ~[]byte](v T) {\n    v[0] = 'x'  \u002F\u002F ❌ строка неизменяемая\n}\n",[65,2186,2187,2224,2237,2241,2245,2276,2299],{"__ignoreMap":5},[68,2188,2189,2191,2194,2196,2198,2201,2203,2205,2207,2209,2212,2214,2216,2218,2220,2222],{"class":70,"line":71},[68,2190,82],{"class":81},[68,2192,2193],{"class":85}," first",[68,2195,232],{"class":89},[68,2197,235],{"class":93},[68,2199,2200],{"class":81}," ~",[68,2202,576],{"class":81},[68,2204,240],{"class":81},[68,2206,2200],{"class":81},[68,2208,2174],{"class":89},[68,2210,2211],{"class":81},"byte",[68,2213,245],{"class":89},[68,2215,708],{"class":93},[68,2217,254],{"class":85},[68,2219,106],{"class":89},[68,2221,2211],{"class":81},[68,2223,112],{"class":89},[68,2225,2226,2228,2230,2232,2234],{"class":70,"line":78},[68,2227,139],{"class":81},[68,2229,2148],{"class":89},[68,2231,2151],{"class":302},[68,2233,1905],{"class":89},[68,2235,2236],{"class":74},"\u002F\u002F ✅ читать можно\n",[68,2238,2239],{"class":70,"line":115},[68,2240,148],{"class":89},[68,2242,2243],{"class":70,"line":136},[68,2244,155],{"emptyLinePlaceholder":154},[68,2246,2247,2249,2252,2254,2256,2258,2260,2262,2264,2266,2268,2270,2272,2274],{"class":70,"line":145},[68,2248,82],{"class":81},[68,2250,2251],{"class":85}," setFirst",[68,2253,232],{"class":89},[68,2255,235],{"class":93},[68,2257,2200],{"class":81},[68,2259,576],{"class":81},[68,2261,240],{"class":81},[68,2263,2200],{"class":81},[68,2265,2174],{"class":89},[68,2267,2211],{"class":81},[68,2269,245],{"class":89},[68,2271,708],{"class":93},[68,2273,254],{"class":85},[68,2275,1691],{"class":89},[68,2277,2278,2281,2283,2285,2287,2290,2293,2296],{"class":70,"line":151},[68,2279,2280],{"class":89},"    v[",[68,2282,2151],{"class":302},[68,2284,1309],{"class":89},[68,2286,1699],{"class":81},[68,2288,2289],{"class":1157}," '",[68,2291,2292],{"class":302},"x",[68,2294,2295],{"class":1157},"'",[68,2297,2298],{"class":74},"  \u002F\u002F ❌ строка неизменяемая\n",[68,2300,2301],{"class":70,"line":158},[68,2302,148],{"class":89},[339,2304,2305,1018,2307,2310],{},[65,2306,576],{},[65,2308,2309],{},"[]byte"," можно объединить в constraint для операций чтения. Запись через индекс не компилируется — строки иммутабельны.",[50,2312,2314],{"id":2313},"метод-типа-не-в-constraint-недоступен","Метод типа не в constraint — недоступен",[59,2316,2318],{"className":61,"code":2317,"language":63,"meta":5,"style":5},"type S struct{}\nfunc (S) Foo() {}\nfunc (S) Bar() {}\n\ntype C interface {\n    ~struct{}\n    Foo()        \u002F\u002F только Foo в constraint\n}\n\nfunc process[T C](v T) {\n    v.Foo()  \u002F\u002F ✅\n    v.Bar()  \u002F\u002F ❌ Bar не в constraint, хотя у S есть\n}\n",[65,2319,2320,2331,2348,2363,2367,2378,2385,2395,2399,2403,2423,2435,2447],{"__ignoreMap":5},[68,2321,2322,2324,2327,2329],{"class":70,"line":71},[68,2323,493],{"class":81},[68,2325,2326],{"class":85}," S",[68,2328,1604],{"class":81},[68,2330,1607],{"class":89},[68,2332,2333,2335,2337,2340,2342,2345],{"class":70,"line":78},[68,2334,82],{"class":81},[68,2336,1623],{"class":89},[68,2338,2339],{"class":85},"S",[68,2341,106],{"class":89},[68,2343,2344],{"class":85},"Foo",[68,2346,2347],{"class":89},"() {}\n",[68,2349,2350,2352,2354,2356,2358,2361],{"class":70,"line":115},[68,2351,82],{"class":81},[68,2353,1623],{"class":89},[68,2355,2339],{"class":85},[68,2357,106],{"class":89},[68,2359,2360],{"class":85},"Bar",[68,2362,2347],{"class":89},[68,2364,2365],{"class":70,"line":136},[68,2366,155],{"emptyLinePlaceholder":154},[68,2368,2369,2371,2374,2376],{"class":70,"line":145},[68,2370,493],{"class":81},[68,2372,2373],{"class":85}," C",[68,2375,499],{"class":81},[68,2377,112],{"class":89},[68,2379,2380,2383],{"class":70,"line":151},[68,2381,2382],{"class":81},"    ~struct",[68,2384,1607],{"class":89},[68,2386,2387,2390,2392],{"class":70,"line":158},[68,2388,2389],{"class":85},"    Foo",[68,2391,1233],{"class":89},[68,2393,2394],{"class":74},"\u002F\u002F только Foo в constraint\n",[68,2396,2397],{"class":70,"line":184},[68,2398,148],{"class":89},[68,2400,2401],{"class":70,"line":199},[68,2402,155],{"emptyLinePlaceholder":154},[68,2404,2405,2407,2409,2411,2413,2415,2417,2419,2421],{"class":70,"line":206},[68,2406,82],{"class":81},[68,2408,1727],{"class":85},[68,2410,232],{"class":89},[68,2412,235],{"class":93},[68,2414,2373],{"class":85},[68,2416,245],{"class":89},[68,2418,708],{"class":93},[68,2420,254],{"class":85},[68,2422,1691],{"class":89},[68,2424,2426,2429,2431,2433],{"class":70,"line":2425},11,[68,2427,2428],{"class":89},"    v.",[68,2430,2344],{"class":85},[68,2432,1278],{"class":89},[68,2434,1985],{"class":74},[68,2436,2438,2440,2442,2444],{"class":70,"line":2437},12,[68,2439,2428],{"class":89},[68,2441,2360],{"class":85},[68,2443,1278],{"class":89},[68,2445,2446],{"class":74},"\u002F\u002F ❌ Bar не в constraint, хотя у S есть\n",[68,2448,2450],{"class":70,"line":2449},13,[68,2451,148],{"class":89},[339,2453,2454,2455,2457,2458,2461],{},"Компилятор знает только то, что гарантирует constraint. Даже если реальный тип имеет метод ",[65,2456,2360],{},", вызов ",[65,2459,2460],{},"v.Bar()"," — ошибка компиляции.",[42,2463],{},[11,2465,2466,2475,2484,2490,2496],{},[14,2467,2468,2471,2472],{},[18,2469,2470],{},"структуры"," могут быть обобщёнными: ",[65,2473,2474],{},"type Set[T comparable] struct { m map[T]struct{} }",[14,2476,2477,2480,2481],{},[18,2478,2479],{},"методы"," обобщённой структуры — в ресивере указывается тип: ",[65,2482,2483],{},"func (s *Set[T]) Add(v T)",[14,2485,2486,2489],{},[18,2487,2488],{},"type definitions"," могут быть обобщёнными и частично инстанцированными",[14,2491,2492,2495],{},[18,2493,2494],{},"type aliases"," не могут быть обобщёнными (до Go 1.24)",[14,2497,2498,2501],{},[18,2499,2500],{},"variadic + generics"," — функция с разным количеством аргументов разных типов при разных вызовах",[42,2503],{},[50,2505,2507],{"id":2506},"обобщённые-типы-и-структуры","Обобщённые типы и структуры",[50,2509,2511],{"id":2510},"обобщённая-структура","Обобщённая структура",[59,2513,2515],{"className":61,"code":2514,"language":63,"meta":5,"style":5},"type Set[T comparable] struct {\n    m map[T]struct{}\n}\n\nfunc NewSet[T comparable]() *Set[T] {\n    return &Set[T]{m: make(map[T]struct{})}\n}\n\n\u002F\u002F Метод — тип в ресивере\nfunc (s *Set[T]) Add(v T) {\n    s.m[v] = struct{}{}\n}\n\n\u002F\u002F Если тип не нужен — пропустить\nfunc (s *Set[_]) Len() int {\n    return len(s.m)\n}\n\n\u002F\u002F Использование — инстанцируем один раз\ns := NewSet[string]()  \u002F\u002F дальше компилятор знает тип\ns.Add(\"hello\")\n",[65,2516,2517,2536,2554,2558,2562,2589,2622,2626,2630,2635,2665,2677,2681,2685,2691,2720,2731,2736,2741,2747,2767],{"__ignoreMap":5},[68,2518,2519,2521,2524,2526,2528,2530,2532,2534],{"class":70,"line":71},[68,2520,493],{"class":81},[68,2522,2523],{"class":85}," Set",[68,2525,232],{"class":89},[68,2527,235],{"class":93},[68,2529,963],{"class":85},[68,2531,1309],{"class":89},[68,2533,1312],{"class":81},[68,2535,112],{"class":89},[68,2537,2538,2541,2544,2546,2548,2550,2552],{"class":70,"line":78},[68,2539,2540],{"class":89},"    m ",[68,2542,2543],{"class":81},"map",[68,2545,232],{"class":89},[68,2547,235],{"class":85},[68,2549,985],{"class":89},[68,2551,1312],{"class":81},[68,2553,1607],{"class":89},[68,2555,2556],{"class":70,"line":115},[68,2557,148],{"class":89},[68,2559,2560],{"class":70,"line":136},[68,2561,155],{"emptyLinePlaceholder":154},[68,2563,2564,2566,2569,2571,2573,2575,2577,2579,2582,2584,2586],{"class":70,"line":145},[68,2565,82],{"class":81},[68,2567,2568],{"class":85}," NewSet",[68,2570,232],{"class":89},[68,2572,235],{"class":93},[68,2574,963],{"class":85},[68,2576,1189],{"class":89},[68,2578,1192],{"class":81},[68,2580,2581],{"class":85},"Set",[68,2583,232],{"class":89},[68,2585,235],{"class":85},[68,2587,2588],{"class":89},"] {\n",[68,2590,2591,2593,2595,2597,2599,2601,2604,2607,2609,2611,2613,2615,2617,2619],{"class":70,"line":151},[68,2592,139],{"class":81},[68,2594,1214],{"class":81},[68,2596,2581],{"class":85},[68,2598,232],{"class":89},[68,2600,235],{"class":85},[68,2602,2603],{"class":89},"]{m: ",[68,2605,2606],{"class":85},"make",[68,2608,90],{"class":89},[68,2610,2543],{"class":81},[68,2612,232],{"class":89},[68,2614,235],{"class":85},[68,2616,985],{"class":89},[68,2618,1312],{"class":81},[68,2620,2621],{"class":89},"{})}\n",[68,2623,2624],{"class":70,"line":158},[68,2625,148],{"class":89},[68,2627,2628],{"class":70,"line":184},[68,2629,155],{"emptyLinePlaceholder":154},[68,2631,2632],{"class":70,"line":199},[68,2633,2634],{"class":74},"\u002F\u002F Метод — тип в ресивере\n",[68,2636,2637,2639,2641,2643,2645,2647,2649,2651,2654,2657,2659,2661,2663],{"class":70,"line":206},[68,2638,82],{"class":81},[68,2640,1623],{"class":89},[68,2642,1626],{"class":93},[68,2644,1192],{"class":81},[68,2646,2581],{"class":85},[68,2648,232],{"class":89},[68,2650,235],{"class":85},[68,2652,2653],{"class":89},"]) ",[68,2655,2656],{"class":85},"Add",[68,2658,90],{"class":89},[68,2660,708],{"class":93},[68,2662,254],{"class":85},[68,2664,1691],{"class":89},[68,2666,2667,2670,2672,2674],{"class":70,"line":2425},[68,2668,2669],{"class":89},"    s.m[v] ",[68,2671,1699],{"class":81},[68,2673,1604],{"class":81},[68,2675,2676],{"class":89},"{}{}\n",[68,2678,2679],{"class":70,"line":2437},[68,2680,148],{"class":89},[68,2682,2683],{"class":70,"line":2449},[68,2684,155],{"emptyLinePlaceholder":154},[68,2686,2688],{"class":70,"line":2687},14,[68,2689,2690],{"class":74},"\u002F\u002F Если тип не нужен — пропустить\n",[68,2692,2694,2696,2698,2700,2702,2704,2706,2709,2711,2714,2716,2718],{"class":70,"line":2693},15,[68,2695,82],{"class":81},[68,2697,1623],{"class":89},[68,2699,1626],{"class":93},[68,2701,1192],{"class":81},[68,2703,2581],{"class":85},[68,2705,232],{"class":89},[68,2707,2708],{"class":85},"_",[68,2710,2653],{"class":89},[68,2712,2713],{"class":85},"Len",[68,2715,573],{"class":89},[68,2717,109],{"class":81},[68,2719,112],{"class":89},[68,2721,2723,2725,2728],{"class":70,"line":2722},16,[68,2724,139],{"class":81},[68,2726,2727],{"class":85}," len",[68,2729,2730],{"class":89},"(s.m)\n",[68,2732,2734],{"class":70,"line":2733},17,[68,2735,148],{"class":89},[68,2737,2739],{"class":70,"line":2738},18,[68,2740,155],{"emptyLinePlaceholder":154},[68,2742,2744],{"class":70,"line":2743},19,[68,2745,2746],{"class":74},"\u002F\u002F Использование — инстанцируем один раз\n",[68,2748,2750,2752,2755,2757,2759,2761,2764],{"class":70,"line":2749},20,[68,2751,1626],{"class":89},[68,2753,2754],{"class":81},":=",[68,2756,2568],{"class":85},[68,2758,232],{"class":89},[68,2760,576],{"class":81},[68,2762,2763],{"class":89},"]()  ",[68,2765,2766],{"class":74},"\u002F\u002F дальше компилятор знает тип\n",[68,2768,2770,2773,2775,2777,2779],{"class":70,"line":2769},21,[68,2771,2772],{"class":89},"s.",[68,2774,2656],{"class":85},[68,2776,90],{"class":89},[68,2778,1158],{"class":1157},[68,2780,2781],{"class":89},")\n",[339,2783,2784,2785,2787,2788,2791,2792,2794,2795,587],{},"Структура параметризована типом ",[65,2786,235],{},". В методах ресивер пишется как ",[65,2789,2790],{},"Set[T]",", а не ",[65,2793,2581],{},". Если параметр типа в методе не нужен — можно использовать ",[65,2796,2708],{},[50,2798,2800],{"id":2799},"обобщённые-type-definitions","Обобщённые type definitions",[59,2802,2804],{"className":61,"code":2803,"language":63,"meta":5,"style":5},"type Pair[T, U any] struct { First T; Second U }\n\n\u002F\u002F Полное инстанцирование\ntype StringIntPair = Pair[string, int]\n\n\u002F\u002F Частичное — через type definition (не alias!)\ntype StringPair[U any] Pair[string, U]\n\u002F\u002F StringPair[int] → Pair[string, int]\n",[65,2805,2806,2840,2844,2849,2871,2875,2880,2908],{"__ignoreMap":5},[68,2807,2808,2810,2813,2815,2817,2819,2822,2824,2826,2828,2831,2833,2836,2838],{"class":70,"line":71},[68,2809,493],{"class":81},[68,2811,2812],{"class":85}," Pair",[68,2814,232],{"class":89},[68,2816,235],{"class":93},[68,2818,97],{"class":89},[68,2820,2821],{"class":93},"U",[68,2823,373],{"class":85},[68,2825,1309],{"class":89},[68,2827,1312],{"class":81},[68,2829,2830],{"class":89}," { First ",[68,2832,235],{"class":85},[68,2834,2835],{"class":89},"; Second ",[68,2837,2821],{"class":85},[68,2839,999],{"class":89},[68,2841,2842],{"class":70,"line":78},[68,2843,155],{"emptyLinePlaceholder":154},[68,2845,2846],{"class":70,"line":115},[68,2847,2848],{"class":74},"\u002F\u002F Полное инстанцирование\n",[68,2850,2851,2853,2856,2858,2860,2862,2864,2866,2868],{"class":70,"line":136},[68,2852,493],{"class":81},[68,2854,2855],{"class":85}," StringIntPair",[68,2857,1273],{"class":81},[68,2859,2812],{"class":85},[68,2861,232],{"class":89},[68,2863,576],{"class":81},[68,2865,97],{"class":89},[68,2867,109],{"class":81},[68,2869,2870],{"class":89},"]\n",[68,2872,2873],{"class":70,"line":145},[68,2874,155],{"emptyLinePlaceholder":154},[68,2876,2877],{"class":70,"line":151},[68,2878,2879],{"class":74},"\u002F\u002F Частичное — через type definition (не alias!)\n",[68,2881,2882,2884,2887,2889,2891,2893,2895,2898,2900,2902,2904,2906],{"class":70,"line":158},[68,2883,493],{"class":81},[68,2885,2886],{"class":85}," StringPair",[68,2888,232],{"class":89},[68,2890,2821],{"class":93},[68,2892,373],{"class":85},[68,2894,1309],{"class":89},[68,2896,2897],{"class":85},"Pair",[68,2899,232],{"class":89},[68,2901,576],{"class":81},[68,2903,97],{"class":89},[68,2905,2821],{"class":85},[68,2907,2870],{"class":89},[68,2909,2910],{"class":70,"line":184},[68,2911,2912],{"class":74},"\u002F\u002F StringPair[int] → Pair[string, int]\n",[339,2914,2915,2916,2919,2920,2923,2924,2927,2928,2930,2931,2933],{},"Частичное инстанцирование возможно только через ",[65,2917,2918],{},"type definition",", не через ",[65,2921,2922],{},"type alias",". ",[65,2925,2926],{},"StringPair[U any]"," фиксирует первый параметр как ",[65,2929,576],{},", оставляя ",[65,2932,2821],{}," свободным.",[50,2935,2937],{"id":2936},"type-aliases-не-обобщённые-до-go-124","Type aliases — не обобщённые (до Go 1.24)",[59,2939,2941],{"className":61,"code":2940,"language":63,"meta":5,"style":5},"type MySlice[T any] []T                 \u002F\u002F ✅ type definition\ntype MyAlias[T any] = []T               \u002F\u002F ❌ до Go 1.24\n",[65,2942,2943,2964],{"__ignoreMap":5},[68,2944,2945,2947,2950,2952,2954,2956,2959,2961],{"class":70,"line":71},[68,2946,493],{"class":81},[68,2948,2949],{"class":85}," MySlice",[68,2951,232],{"class":89},[68,2953,235],{"class":93},[68,2955,373],{"class":85},[68,2957,2958],{"class":89},"] []",[68,2960,235],{"class":85},[68,2962,2963],{"class":74},"                 \u002F\u002F ✅ type definition\n",[68,2965,2966,2968,2971,2973,2975,2977,2979,2981,2983,2985],{"class":70,"line":78},[68,2967,493],{"class":81},[68,2969,2970],{"class":85}," MyAlias",[68,2972,232],{"class":89},[68,2974,235],{"class":93},[68,2976,373],{"class":85},[68,2978,1309],{"class":89},[68,2980,1699],{"class":81},[68,2982,2127],{"class":89},[68,2984,235],{"class":85},[68,2986,2987],{"class":74},"               \u002F\u002F ❌ до Go 1.24\n",[339,2989,2990],{},"С Go 1.24 обобщённые aliases поддерживаются.",[50,2992,2994],{"id":2993},"прятать-сложность-за-aliasdefinition","Прятать сложность за alias\u002Fdefinition",[59,2996,2998],{"className":61,"code":2997,"language":63,"meta":5,"style":5},"type IntSet = Set[int]           \u002F\u002F простой alias для пользователя\ntype OrderedMap[K comparable, V any] struct { ... }  \u002F\u002F внутри сложно\n\n\u002F\u002F Для constraints тоже:\ntype Numeric interface { ~int | ~float64 }\n",[65,2999,3000,3021,3053,3057,3062],{"__ignoreMap":5},[68,3001,3002,3004,3007,3009,3011,3013,3015,3018],{"class":70,"line":71},[68,3003,493],{"class":81},[68,3005,3006],{"class":85}," IntSet",[68,3008,1273],{"class":81},[68,3010,2523],{"class":85},[68,3012,232],{"class":89},[68,3014,109],{"class":81},[68,3016,3017],{"class":89},"]           ",[68,3019,3020],{"class":74},"\u002F\u002F простой alias для пользователя\n",[68,3022,3023,3025,3028,3030,3032,3034,3036,3038,3040,3042,3044,3046,3048,3050],{"class":70,"line":78},[68,3024,493],{"class":81},[68,3026,3027],{"class":85}," OrderedMap",[68,3029,232],{"class":89},[68,3031,960],{"class":93},[68,3033,963],{"class":85},[68,3035,97],{"class":89},[68,3037,968],{"class":93},[68,3039,373],{"class":85},[68,3041,1309],{"class":89},[68,3043,1312],{"class":81},[68,3045,381],{"class":89},[68,3047,384],{"class":81},[68,3049,387],{"class":89},[68,3051,3052],{"class":74},"\u002F\u002F внутри сложно\n",[68,3054,3055],{"class":70,"line":115},[68,3056,155],{"emptyLinePlaceholder":154},[68,3058,3059],{"class":70,"line":136},[68,3060,3061],{"class":74},"\u002F\u002F Для constraints тоже:\n",[68,3063,3064,3066,3069,3071,3073,3075,3077,3079],{"class":70,"line":145},[68,3065,493],{"class":81},[68,3067,3068],{"class":85}," Numeric",[68,3070,499],{"class":81},[68,3072,381],{"class":89},[68,3074,441],{"class":81},[68,3076,240],{"class":81},[68,3078,562],{"class":81},[68,3080,999],{"class":89},[339,3082,3083],{},"Техника: сложный обобщённый тип прячется за простым именем через alias или частичное инстанцирование.",[50,3085,3087],{"id":3086},"variadic-generics","Variadic + generics",[59,3089,3091],{"className":61,"code":3090,"language":63,"meta":5,"style":5},"func printAll[T any](vals ...T) {\n    for _, v := range vals { fmt.Println(v) }\n}\n\nprintAll(1, 2, 3)           \u002F\u002F T=int, 3 аргумента\nprintAll(\"a\", \"b\")          \u002F\u002F T=string, 2 аргумента\nprintAll(1.0, 2.0, 3.0, 4.0) \u002F\u002F T=float64, 4 аргумента\n",[65,3092,3093,3118,3140,3144,3148,3172,3191],{"__ignoreMap":5},[68,3094,3095,3097,3100,3102,3104,3106,3108,3111,3114,3116],{"class":70,"line":71},[68,3096,82],{"class":81},[68,3098,3099],{"class":85}," printAll",[68,3101,232],{"class":89},[68,3103,235],{"class":93},[68,3105,373],{"class":85},[68,3107,245],{"class":89},[68,3109,3110],{"class":93},"vals",[68,3112,3113],{"class":81}," ...",[68,3115,235],{"class":85},[68,3117,1691],{"class":89},[68,3119,3120,3123,3126,3128,3131,3134,3137],{"class":70,"line":78},[68,3121,3122],{"class":81},"    for",[68,3124,3125],{"class":89}," _, v ",[68,3127,2754],{"class":81},[68,3129,3130],{"class":81}," range",[68,3132,3133],{"class":89}," vals { fmt.",[68,3135,3136],{"class":85},"Println",[68,3138,3139],{"class":89},"(v) }\n",[68,3141,3142],{"class":70,"line":115},[68,3143,148],{"class":89},[68,3145,3146],{"class":70,"line":136},[68,3147,155],{"emptyLinePlaceholder":154},[68,3149,3150,3153,3155,3157,3159,3161,3163,3166,3169],{"class":70,"line":145},[68,3151,3152],{"class":85},"printAll",[68,3154,90],{"class":89},[68,3156,303],{"class":302},[68,3158,97],{"class":89},[68,3160,308],{"class":302},[68,3162,97],{"class":89},[68,3164,3165],{"class":302},"3",[68,3167,3168],{"class":89},")           ",[68,3170,3171],{"class":74},"\u002F\u002F T=int, 3 аргумента\n",[68,3173,3174,3176,3178,3181,3183,3186,3188],{"class":70,"line":151},[68,3175,3152],{"class":85},[68,3177,90],{"class":89},[68,3179,3180],{"class":1157},"\"a\"",[68,3182,97],{"class":89},[68,3184,3185],{"class":1157},"\"b\"",[68,3187,1145],{"class":89},[68,3189,3190],{"class":74},"\u002F\u002F T=string, 2 аргумента\n",[68,3192,3193,3195,3197,3200,3202,3205,3207,3210,3212,3215,3217],{"class":70,"line":158},[68,3194,3152],{"class":85},[68,3196,90],{"class":89},[68,3198,3199],{"class":302},"1.0",[68,3201,97],{"class":89},[68,3203,3204],{"class":302},"2.0",[68,3206,97],{"class":89},[68,3208,3209],{"class":302},"3.0",[68,3211,97],{"class":89},[68,3213,3214],{"class":302},"4.0",[68,3216,106],{"class":89},[68,3218,3219],{"class":74},"\u002F\u002F T=float64, 4 аргумента\n",[339,3221,3222],{},"Все аргументы одного типа (variadic), но тип и количество меняются от вызова к вызову. Тип выводится из первого аргумента.",[50,3224,3226],{"id":3225},"обобщённые-constraints-template-template-parameters","Обобщённые constraints (template template parameters)",[59,3228,3230],{"className":61,"code":3229,"language":63,"meta":5,"style":5},"type Unsigned interface { ~uint | ~uint8 | ~uint16 }\n\ntype Slice[T any] []T\n\ntype SliceConstraint[E Unsigned] interface {\n    ~[]E  \u002F\u002F срез из unsigned-элементов\n}\n\nfunc do[E Unsigned, S SliceConstraint[E]](s S) { ... }\n",[65,3231,3232,3258,3262,3279,3283,3303,3315,3319,3323],{"__ignoreMap":5},[68,3233,3234,3236,3239,3241,3243,3246,3248,3251,3253,3256],{"class":70,"line":71},[68,3235,493],{"class":81},[68,3237,3238],{"class":85}," Unsigned",[68,3240,499],{"class":81},[68,3242,381],{"class":89},[68,3244,3245],{"class":81},"~uint",[68,3247,240],{"class":81},[68,3249,3250],{"class":81}," ~uint8",[68,3252,240],{"class":81},[68,3254,3255],{"class":81}," ~uint16",[68,3257,999],{"class":89},[68,3259,3260],{"class":70,"line":78},[68,3261,155],{"emptyLinePlaceholder":154},[68,3263,3264,3266,3269,3271,3273,3275,3277],{"class":70,"line":115},[68,3265,493],{"class":81},[68,3267,3268],{"class":85}," Slice",[68,3270,232],{"class":89},[68,3272,235],{"class":93},[68,3274,373],{"class":85},[68,3276,2958],{"class":89},[68,3278,1207],{"class":85},[68,3280,3281],{"class":70,"line":136},[68,3282,155],{"emptyLinePlaceholder":154},[68,3284,3285,3287,3290,3292,3294,3296,3298,3301],{"class":70,"line":145},[68,3286,493],{"class":81},[68,3288,3289],{"class":85}," SliceConstraint",[68,3291,232],{"class":89},[68,3293,1394],{"class":93},[68,3295,3238],{"class":85},[68,3297,1309],{"class":89},[68,3299,3300],{"class":81},"interface",[68,3302,112],{"class":89},[68,3304,3305,3308,3310,3312],{"class":70,"line":151},[68,3306,3307],{"class":81},"    ~",[68,3309,2174],{"class":89},[68,3311,1394],{"class":85},[68,3313,3314],{"class":74},"  \u002F\u002F срез из unsigned-элементов\n",[68,3316,3317],{"class":70,"line":158},[68,3318,148],{"class":89},[68,3320,3321],{"class":70,"line":184},[68,3322,155],{"emptyLinePlaceholder":154},[68,3324,3325,3327,3330,3332,3334,3336,3338,3340,3342,3344,3346,3349,3351,3353,3355,3357],{"class":70,"line":199},[68,3326,82],{"class":81},[68,3328,3329],{"class":85}," do",[68,3331,232],{"class":89},[68,3333,1394],{"class":93},[68,3335,3238],{"class":85},[68,3337,97],{"class":89},[68,3339,2339],{"class":93},[68,3341,3289],{"class":85},[68,3343,232],{"class":89},[68,3345,1394],{"class":85},[68,3347,3348],{"class":89},"]](",[68,3350,1677],{"class":93},[68,3352,2326],{"class":85},[68,3354,1106],{"class":89},[68,3356,384],{"class":81},[68,3358,999],{"class":89},[339,3360,3361,3362,3364,3365,3367],{},"Редкий случай — когда нужно достучаться до типа внутри обобщённого контейнера. ",[65,3363,2339],{}," здесь — constraint, параметризованный другим type-параметром ",[65,3366,1394],{},". Аналог template template parameters из C++.",[42,3369],{},[11,3371,3372,3379,3390,3397,3403,3409],{},[14,3373,3374,3375,3378],{},"сигнал: пишете ",[18,3376,3377],{},"один и тот же код"," несколько раз, отличаются только типы → дженерики",[14,3380,3381,3382,3385,3386,3389],{},"идеальные кейсы: ",[18,3383,3384],{},"структуры данных"," (Set, Tree, Graph), ",[18,3387,3388],{},"функции контейнеров"," (sort, merge, filter)",[14,3391,3392,3393,3396],{},"цена: ",[18,3394,3395],{},"рост бинарника"," (каждая специализация = новый код в ассемблере)",[14,3398,3392,3399,3402],{},[18,3400,3401],{},"увеличение времени компиляции"," (генерация кода для каждого типа)",[14,3404,3405,3406,3408],{},"редкий случай: компилятор может подставить ",[18,3407,420],{}," вместо инстанцирования (когда много типов)",[14,3410,3411,3412,3415],{},"рантайм оверхед = ",[18,3413,3414],{},"ноль"," (код как если бы написали руками для конкретного типа)",[42,3417],{},[50,3419,3421],{"id":3420},"когда-применять-дженерики","Когда применять дженерики",[50,3423,3425],{"id":3424},"когда-использовать","Когда использовать",[59,3427,3429],{"className":61,"code":3428,"language":63,"meta":5,"style":5},"\u002F\u002F ❌ дублирование — сигнал\nfunc containsInt(s []int, v int) bool { ... }\nfunc containsString(s []string, v string) bool { ... }\n\n\u002F\u002F ✅ дженерик\nfunc contains[T comparable](s []T, v T) bool {\n    for _, item := range s {\n        if item == v { return true }\n    }\n    return false\n}\n",[65,3430,3431,3436,3468,3500,3504,3509,3542,3556,3576,3581,3588],{"__ignoreMap":5},[68,3432,3433],{"class":70,"line":71},[68,3434,3435],{"class":74},"\u002F\u002F ❌ дублирование — сигнал\n",[68,3437,3438,3440,3443,3445,3447,3449,3451,3453,3455,3457,3459,3462,3464,3466],{"class":70,"line":78},[68,3439,82],{"class":81},[68,3441,3442],{"class":85}," containsInt",[68,3444,90],{"class":89},[68,3446,1677],{"class":93},[68,3448,2127],{"class":89},[68,3450,109],{"class":81},[68,3452,97],{"class":89},[68,3454,708],{"class":93},[68,3456,103],{"class":81},[68,3458,106],{"class":89},[68,3460,3461],{"class":81},"bool",[68,3463,381],{"class":89},[68,3465,384],{"class":81},[68,3467,999],{"class":89},[68,3469,3470,3472,3475,3477,3479,3481,3483,3485,3487,3490,3492,3494,3496,3498],{"class":70,"line":115},[68,3471,82],{"class":81},[68,3473,3474],{"class":85}," containsString",[68,3476,90],{"class":89},[68,3478,1677],{"class":93},[68,3480,2127],{"class":89},[68,3482,576],{"class":81},[68,3484,97],{"class":89},[68,3486,708],{"class":93},[68,3488,3489],{"class":81}," string",[68,3491,106],{"class":89},[68,3493,3461],{"class":81},[68,3495,381],{"class":89},[68,3497,384],{"class":81},[68,3499,999],{"class":89},[68,3501,3502],{"class":70,"line":136},[68,3503,155],{"emptyLinePlaceholder":154},[68,3505,3506],{"class":70,"line":145},[68,3507,3508],{"class":74},"\u002F\u002F ✅ дженерик\n",[68,3510,3511,3513,3516,3518,3520,3522,3524,3526,3528,3530,3532,3534,3536,3538,3540],{"class":70,"line":151},[68,3512,82],{"class":81},[68,3514,3515],{"class":85}," contains",[68,3517,232],{"class":89},[68,3519,235],{"class":93},[68,3521,963],{"class":85},[68,3523,245],{"class":89},[68,3525,1677],{"class":93},[68,3527,2127],{"class":89},[68,3529,235],{"class":85},[68,3531,97],{"class":89},[68,3533,708],{"class":93},[68,3535,254],{"class":85},[68,3537,106],{"class":89},[68,3539,3461],{"class":81},[68,3541,112],{"class":89},[68,3543,3544,3546,3549,3551,3553],{"class":70,"line":158},[68,3545,3122],{"class":81},[68,3547,3548],{"class":89}," _, item ",[68,3550,2754],{"class":81},[68,3552,3130],{"class":81},[68,3554,3555],{"class":89}," s {\n",[68,3557,3558,3561,3564,3566,3569,3571,3574],{"class":70,"line":184},[68,3559,3560],{"class":81},"        if",[68,3562,3563],{"class":89}," item ",[68,3565,1017],{"class":81},[68,3567,3568],{"class":89}," v { ",[68,3570,130],{"class":81},[68,3572,3573],{"class":302}," true",[68,3575,999],{"class":89},[68,3577,3578],{"class":70,"line":199},[68,3579,3580],{"class":89},"    }\n",[68,3582,3583,3585],{"class":70,"line":206},[68,3584,139],{"class":81},[68,3586,3587],{"class":302}," false\n",[68,3589,3590],{"class":70,"line":2425},[68,3591,148],{"class":89},[50,3593,3595],{"id":3594},"идеальные-кейсы","Идеальные кейсы",[339,3597,3598],{},"Структуры данных: Set, Heap, BinaryTree, Graph — параметризованы типом элемента.",[339,3600,3601],{},"Функции контейнеров: Map, Filter, Reduce, Sort для срезов\u002Fканалов любых типов.",[339,3603,3604,3605,587],{},"Обобщённые обёртки: unsafe.Pointer → типизированный, atomic.Pointer",[68,3606,235],{},[50,3608,3610],{"id":3609},"рост-бинарника","Рост бинарника",[59,3612,3614],{"className":61,"code":3613,"language":63,"meta":5,"style":5},"func sum[T int | float64](a, b T) T { return a + b }\n\nsum[int](1, 2)\nsum[float64](1.0, 2.0)\n",[65,3615,3616,3656,3660,3679],{"__ignoreMap":5},[68,3617,3618,3620,3622,3624,3626,3628,3630,3632,3634,3636,3638,3640,3642,3644,3646,3648,3650,3652,3654],{"class":70,"line":71},[68,3619,82],{"class":81},[68,3621,800],{"class":85},[68,3623,232],{"class":89},[68,3625,235],{"class":93},[68,3627,103],{"class":81},[68,3629,240],{"class":81},[68,3631,511],{"class":81},[68,3633,245],{"class":89},[68,3635,94],{"class":93},[68,3637,97],{"class":89},[68,3639,100],{"class":93},[68,3641,254],{"class":85},[68,3643,106],{"class":89},[68,3645,235],{"class":85},[68,3647,381],{"class":89},[68,3649,130],{"class":81},[68,3651,121],{"class":89},[68,3653,829],{"class":81},[68,3655,832],{"class":89},[68,3657,3658],{"class":70,"line":78},[68,3659,155],{"emptyLinePlaceholder":154},[68,3661,3662,3665,3667,3669,3671,3673,3675,3677],{"class":70,"line":115},[68,3663,3664],{"class":85},"sum",[68,3666,232],{"class":89},[68,3668,109],{"class":81},[68,3670,245],{"class":89},[68,3672,303],{"class":302},[68,3674,97],{"class":89},[68,3676,308],{"class":302},[68,3678,2781],{"class":89},[68,3680,3681,3683,3685,3688,3690,3692,3694,3696],{"class":70,"line":136},[68,3682,3664],{"class":85},[68,3684,232],{"class":89},[68,3686,3687],{"class":81},"float64",[68,3689,245],{"class":89},[68,3691,3199],{"class":302},[68,3693,97],{"class":89},[68,3695,3204],{"class":302},[68,3697,2781],{"class":89},[339,3699,3700,3701,3704,3705,1018,3708,3711],{},"В ассемблере будут ",[18,3702,3703],{},"две"," функции: ",[65,3706,3707],{},"sum[int]",[65,3709,3710],{},"sum[float64]"," с разными инструкциями. Бинарник растёт линейно от количества инстанцирований.",[50,3713,3715],{"id":3714},"интерфейсный-fallback","Интерфейсный fallback",[339,3717,3718],{},"В редких случаях (много типов) компилятор Go может не инстанцировать, а подставить пустой интерфейс — чтобы не раздувать бинарник.",[339,3720,3721],{},"Это прозрачно для пользователя, но добавляет рантайм-оверхед (boxing).",[50,3723,3725],{"id":3724},"не-усложняй","Не усложняй",[339,3727,3728,3729,3732],{},"Дженерики могут сделать код ",[18,3730,3731],{},"сложнее",". Если нет дублирования — не нужны. Не ищите место, куда «воткнуть дженерик».",[339,3734,3735],{},"В C++ — известная проблема: изучил шаблоны → пишешь всё на шаблонах → через час не разберёшься.",[42,3737],{},[11,3739,3740,3752,3761,3774,3784],{},[14,3741,3742,3745,3746,97,3749,473],{},[18,3743,3744],{},"свойство 1",": от интерфейса → к reflect-объекту (",[65,3747,3748],{},"TypeOf",[65,3750,3751],{},"ValueOf",[14,3753,3754,3757,3758,473],{},[18,3755,3756],{},"свойство 2",": от reflect-объекта → к интерфейсу (метод ",[65,3759,3760],{},"Interface()",[14,3762,3763,3766,3767,3770,3771,473],{},[18,3764,3765],{},"свойство 3",": для ",[18,3768,3769],{},"модификации"," значение должно быть settable (передать указатель + ",[65,3772,3773],{},"Elem()",[14,3775,3776,3779,3780,3783],{},[65,3777,3778],{},"CanSet()"," \u002F ",[65,3781,3782],{},"CanAddr()"," — проверка: можно ли менять значение",[14,3785,3786,3787,3790],{},"копия значения — ",[18,3788,3789],{},"не settable",", нужен указатель → Elem() → тогда settable",[42,3792],{},[45,3794,3796],{"id":3795},"reflect","Reflect",[50,3798,3800],{"id":3799},"основы-reflect","Основы reflect",[50,3802,3804],{"id":3803},"свойство-1-интерфейс-reflect","Свойство 1: интерфейс → reflect",[59,3806,3808],{"className":61,"code":3807,"language":63,"meta":5,"style":5},"var x float64 = 3.14\n\n\u002F\u002F Неявное преобразование x → any → анализ itab + data\nt := reflect.TypeOf(x)   \u002F\u002F reflect.Type\nv := reflect.ValueOf(x)  \u002F\u002F reflect.Value\n",[65,3809,3810,3823,3827,3832,3850],{"__ignoreMap":5},[68,3811,3812,3814,3816,3818,3820],{"class":70,"line":71},[68,3813,1264],{"class":81},[68,3815,1748],{"class":89},[68,3817,3687],{"class":81},[68,3819,1273],{"class":81},[68,3821,3822],{"class":302}," 3.14\n",[68,3824,3825],{"class":70,"line":78},[68,3826,155],{"emptyLinePlaceholder":154},[68,3828,3829],{"class":70,"line":115},[68,3830,3831],{"class":74},"\u002F\u002F Неявное преобразование x → any → анализ itab + data\n",[68,3833,3834,3837,3839,3842,3844,3847],{"class":70,"line":136},[68,3835,3836],{"class":89},"t ",[68,3838,2754],{"class":81},[68,3840,3841],{"class":89}," reflect.",[68,3843,3748],{"class":85},[68,3845,3846],{"class":89},"(x)   ",[68,3848,3849],{"class":74},"\u002F\u002F reflect.Type\n",[68,3851,3852,3855,3857,3859,3861,3864],{"class":70,"line":145},[68,3853,3854],{"class":89},"v ",[68,3856,2754],{"class":81},[68,3858,3841],{"class":89},[68,3860,3751],{"class":85},[68,3862,3863],{"class":89},"(x)  ",[68,3865,3866],{"class":74},"\u002F\u002F reflect.Value\n",[339,3868,3869,3870,3872,3873,97,3876,3878,3879,587],{},"Всё начинается с неявного преобразования в пустой интерфейс. ",[65,3871,3748],{}," возвращает ",[65,3874,3875],{},"reflect.Type",[65,3877,3751],{}," — ",[65,3880,3881],{},"reflect.Value",[50,3883,3885],{"id":3884},"свойство-2-reflect-интерфейс","Свойство 2: reflect → интерфейс",[59,3887,3889],{"className":61,"code":3888,"language":63,"meta":5,"style":5},"package main\n\nimport (\n    \"fmt\"\n    \"reflect\"\n)\n\nfunc main() {\n    var x float64 = 3.14\n    v := reflect.ValueOf(x)\n\n    \u002F\u002F Обратно: reflect.Value → interface{} → float64\n    y := v.Interface().(float64)\n    fmt.Println(y) \u002F\u002F 3.14\n}\n",[65,3890,3891,3899,3903,3911,3922,3930,3934,3938,3948,3960,3974,3978,3983,4003,4016],{"__ignoreMap":5},[68,3892,3893,3896],{"class":70,"line":71},[68,3894,3895],{"class":81},"package",[68,3897,3898],{"class":85}," main\n",[68,3900,3901],{"class":70,"line":78},[68,3902,155],{"emptyLinePlaceholder":154},[68,3904,3905,3908],{"class":70,"line":115},[68,3906,3907],{"class":81},"import",[68,3909,3910],{"class":89}," (\n",[68,3912,3913,3916,3919],{"class":70,"line":136},[68,3914,3915],{"class":1157},"    \"",[68,3917,3918],{"class":85},"fmt",[68,3920,3921],{"class":1157},"\"\n",[68,3923,3924,3926,3928],{"class":70,"line":145},[68,3925,3915],{"class":1157},[68,3927,3795],{"class":85},[68,3929,3921],{"class":1157},[68,3931,3932],{"class":70,"line":151},[68,3933,2781],{"class":89},[68,3935,3936],{"class":70,"line":158},[68,3937,155],{"emptyLinePlaceholder":154},[68,3939,3940,3942,3945],{"class":70,"line":184},[68,3941,82],{"class":81},[68,3943,3944],{"class":85}," main",[68,3946,3947],{"class":89},"() {\n",[68,3949,3950,3952,3954,3956,3958],{"class":70,"line":199},[68,3951,1201],{"class":81},[68,3953,1748],{"class":89},[68,3955,3687],{"class":81},[68,3957,1273],{"class":81},[68,3959,3822],{"class":302},[68,3961,3962,3965,3967,3969,3971],{"class":70,"line":206},[68,3963,3964],{"class":89},"    v ",[68,3966,2754],{"class":81},[68,3968,3841],{"class":89},[68,3970,3751],{"class":85},[68,3972,3973],{"class":89},"(x)\n",[68,3975,3976],{"class":70,"line":2425},[68,3977,155],{"emptyLinePlaceholder":154},[68,3979,3980],{"class":70,"line":2437},[68,3981,3982],{"class":74},"    \u002F\u002F Обратно: reflect.Value → interface{} → float64\n",[68,3984,3985,3988,3990,3993,3996,3999,4001],{"class":70,"line":2449},[68,3986,3987],{"class":89},"    y ",[68,3989,2754],{"class":81},[68,3991,3992],{"class":89}," v.",[68,3994,3995],{"class":85},"Interface",[68,3997,3998],{"class":89},"().(",[68,4000,3687],{"class":81},[68,4002,2781],{"class":89},[68,4004,4005,4008,4010,4013],{"class":70,"line":2687},[68,4006,4007],{"class":89},"    fmt.",[68,4009,3136],{"class":85},[68,4011,4012],{"class":89},"(y) ",[68,4014,4015],{"class":74},"\u002F\u002F 3.14\n",[68,4017,4018],{"class":70,"line":2693},[68,4019,148],{"class":89},[339,4021,4022,4023,4025,4026,587],{},"Метод ",[65,4024,3760],{}," упаковывает тип и значение обратно в интерфейс. Это обратная операция к ",[65,4027,3751],{},[50,4029,4031],{"id":4030},"свойство-3-settable-для-модификации-нужен-указатель","Свойство 3: settable — для модификации нужен указатель",[59,4033,4035],{"className":61,"code":4034,"language":63,"meta":5,"style":5},"var x float64 = 3.14\n\n\u002F\u002F ❌ Копия — нельзя менять\nv := reflect.ValueOf(x)\nfmt.Println(v.CanSet())   \u002F\u002F false\nv.SetFloat(2.0)            \u002F\u002F ПАНИКА: using unaddressable value\n\n\u002F\u002F ❌ Указатель — тоже копия (копия указателя)\nv2 := reflect.ValueOf(&x)\nfmt.Println(v2.CanSet())   \u002F\u002F false — сам указатель копия\n\n\u002F\u002F ✅ Указатель + Elem() — разыменование → оригинал\nv3 := reflect.ValueOf(&x).Elem()\nfmt.Println(v3.CanSet())   \u002F\u002F true!\nv3.SetFloat(2.0)\nfmt.Println(x)              \u002F\u002F 2.0 — оригинал изменился\n",[65,4036,4037,4049,4053,4058,4070,4089,4107,4111,4116,4135,4151,4155,4160,4184,4200,4213],{"__ignoreMap":5},[68,4038,4039,4041,4043,4045,4047],{"class":70,"line":71},[68,4040,1264],{"class":81},[68,4042,1748],{"class":89},[68,4044,3687],{"class":81},[68,4046,1273],{"class":81},[68,4048,3822],{"class":302},[68,4050,4051],{"class":70,"line":78},[68,4052,155],{"emptyLinePlaceholder":154},[68,4054,4055],{"class":70,"line":115},[68,4056,4057],{"class":74},"\u002F\u002F ❌ Копия — нельзя менять\n",[68,4059,4060,4062,4064,4066,4068],{"class":70,"line":136},[68,4061,3854],{"class":89},[68,4063,2754],{"class":81},[68,4065,3841],{"class":89},[68,4067,3751],{"class":85},[68,4069,3973],{"class":89},[68,4071,4072,4075,4077,4080,4083,4086],{"class":70,"line":145},[68,4073,4074],{"class":89},"fmt.",[68,4076,3136],{"class":85},[68,4078,4079],{"class":89},"(v.",[68,4081,4082],{"class":85},"CanSet",[68,4084,4085],{"class":89},"())   ",[68,4087,4088],{"class":74},"\u002F\u002F false\n",[68,4090,4091,4094,4097,4099,4101,4104],{"class":70,"line":151},[68,4092,4093],{"class":89},"v.",[68,4095,4096],{"class":85},"SetFloat",[68,4098,90],{"class":89},[68,4100,3204],{"class":302},[68,4102,4103],{"class":89},")            ",[68,4105,4106],{"class":74},"\u002F\u002F ПАНИКА: using unaddressable value\n",[68,4108,4109],{"class":70,"line":158},[68,4110,155],{"emptyLinePlaceholder":154},[68,4112,4113],{"class":70,"line":184},[68,4114,4115],{"class":74},"\u002F\u002F ❌ Указатель — тоже копия (копия указателя)\n",[68,4117,4118,4121,4123,4125,4127,4129,4132],{"class":70,"line":199},[68,4119,4120],{"class":89},"v2 ",[68,4122,2754],{"class":81},[68,4124,3841],{"class":89},[68,4126,3751],{"class":85},[68,4128,90],{"class":89},[68,4130,4131],{"class":81},"&",[68,4133,4134],{"class":89},"x)\n",[68,4136,4137,4139,4141,4144,4146,4148],{"class":70,"line":206},[68,4138,4074],{"class":89},[68,4140,3136],{"class":85},[68,4142,4143],{"class":89},"(v2.",[68,4145,4082],{"class":85},[68,4147,4085],{"class":89},[68,4149,4150],{"class":74},"\u002F\u002F false — сам указатель копия\n",[68,4152,4153],{"class":70,"line":2425},[68,4154,155],{"emptyLinePlaceholder":154},[68,4156,4157],{"class":70,"line":2437},[68,4158,4159],{"class":74},"\u002F\u002F ✅ Указатель + Elem() — разыменование → оригинал\n",[68,4161,4162,4165,4167,4169,4171,4173,4175,4178,4181],{"class":70,"line":2449},[68,4163,4164],{"class":89},"v3 ",[68,4166,2754],{"class":81},[68,4168,3841],{"class":89},[68,4170,3751],{"class":85},[68,4172,90],{"class":89},[68,4174,4131],{"class":81},[68,4176,4177],{"class":89},"x).",[68,4179,4180],{"class":85},"Elem",[68,4182,4183],{"class":89},"()\n",[68,4185,4186,4188,4190,4193,4195,4197],{"class":70,"line":2687},[68,4187,4074],{"class":89},[68,4189,3136],{"class":85},[68,4191,4192],{"class":89},"(v3.",[68,4194,4082],{"class":85},[68,4196,4085],{"class":89},[68,4198,4199],{"class":74},"\u002F\u002F true!\n",[68,4201,4202,4205,4207,4209,4211],{"class":70,"line":2693},[68,4203,4204],{"class":89},"v3.",[68,4206,4096],{"class":85},[68,4208,90],{"class":89},[68,4210,3204],{"class":302},[68,4212,2781],{"class":89},[68,4214,4215,4217,4219,4222],{"class":70,"line":2722},[68,4216,4074],{"class":89},[68,4218,3136],{"class":85},[68,4220,4221],{"class":89},"(x)              ",[68,4223,4224],{"class":74},"\u002F\u002F 2.0 — оригинал изменился\n",[339,4226,4227,4230,4231,2923,4234,4237,4238,4240,4241,4244,4245,587],{},[65,4228,4229],{},"ValueOf(x)"," — копия, ",[65,4232,4233],{},"CanSet: false",[65,4235,4236],{},"ValueOf(&x)"," — копия указателя, ",[65,4239,4233],{},". Только ",[65,4242,4243],{},"ValueOf(&x).Elem()"," даёт доступ к оригиналу, ",[65,4246,4247],{},"CanSet: true",[339,4249,4250,4251,4253,4254,4257,4258,587],{},"Вызов ",[65,4252,4096],{}," (и любого ",[65,4255,4256],{},"SetXxx",") на non-settable значении вызывает панику с текстом ",[65,4259,4260],{},"using unaddressable value",[50,4262,4264],{"id":4263},"почему-так","Почему так",[339,4266,4267],{},"Аналогия с функциями: если передал значение — функция работает с копией. Если хочешь менять — передай указатель. Рефлексия работает по тому же принципу.",[59,4269,4274],{"className":4270,"code":4272,"language":4273},[4271],"language-text","ValueOf(x)         → копия x          → CanSet: false\nValueOf(&x)        → копия указателя  → CanSet: false\nValueOf(&x).Elem() → оригинал x       → CanSet: true\n","text",[65,4275,4272],{"__ignoreMap":5},[50,4277,4279],{"id":4278},"интерфейсы-дополнительный-elem","Интерфейсы — дополнительный Elem()",[59,4281,4283],{"className":61,"code":4282,"language":63,"meta":5,"style":5},"var z int = 42\nvar iface any = &z\n\nv := reflect.ValueOf(iface)        \u002F\u002F any → копия указателя\nv = v.Elem()                        \u002F\u002F разыменование интерфейса → *int\nv = v.Elem()                        \u002F\u002F разыменование указателя → int\nv.SetInt(100)\nfmt.Println(z)  \u002F\u002F 100\n",[65,4284,4285,4299,4315,4319,4335,4351,4366,4379],{"__ignoreMap":5},[68,4286,4287,4289,4292,4294,4296],{"class":70,"line":71},[68,4288,1264],{"class":81},[68,4290,4291],{"class":89}," z ",[68,4293,109],{"class":81},[68,4295,1273],{"class":81},[68,4297,4298],{"class":302}," 42\n",[68,4300,4301,4303,4306,4308,4310,4312],{"class":70,"line":78},[68,4302,1264],{"class":81},[68,4304,4305],{"class":89}," iface ",[68,4307,378],{"class":85},[68,4309,1273],{"class":81},[68,4311,1214],{"class":81},[68,4313,4314],{"class":89},"z\n",[68,4316,4317],{"class":70,"line":115},[68,4318,155],{"emptyLinePlaceholder":154},[68,4320,4321,4323,4325,4327,4329,4332],{"class":70,"line":136},[68,4322,3854],{"class":89},[68,4324,2754],{"class":81},[68,4326,3841],{"class":89},[68,4328,3751],{"class":85},[68,4330,4331],{"class":89},"(iface)        ",[68,4333,4334],{"class":74},"\u002F\u002F any → копия указателя\n",[68,4336,4337,4339,4341,4343,4345,4348],{"class":70,"line":145},[68,4338,3854],{"class":89},[68,4340,1699],{"class":81},[68,4342,3992],{"class":89},[68,4344,4180],{"class":85},[68,4346,4347],{"class":89},"()                        ",[68,4349,4350],{"class":74},"\u002F\u002F разыменование интерфейса → *int\n",[68,4352,4353,4355,4357,4359,4361,4363],{"class":70,"line":151},[68,4354,3854],{"class":89},[68,4356,1699],{"class":81},[68,4358,3992],{"class":89},[68,4360,4180],{"class":85},[68,4362,4347],{"class":89},[68,4364,4365],{"class":74},"\u002F\u002F разыменование указателя → int\n",[68,4367,4368,4370,4373,4375,4377],{"class":70,"line":158},[68,4369,4093],{"class":89},[68,4371,4372],{"class":85},"SetInt",[68,4374,90],{"class":89},[68,4376,1129],{"class":302},[68,4378,2781],{"class":89},[68,4380,4381,4383,4385,4388],{"class":70,"line":184},[68,4382,4074],{"class":89},[68,4384,3136],{"class":85},[68,4386,4387],{"class":89},"(z)  ",[68,4389,4390],{"class":74},"\u002F\u002F 100\n",[339,4392,4393,4394,4396,4397,4399],{},"Когда значение лежит в интерфейсе — нужен дополнительный ",[65,4395,3773],{}," для разыменования интерфейсного слоя, и ещё один для разыменования указателя. Итого два ",[65,4398,3773],{}," вместо одного.",[42,4401],{},[11,4403,4404,4418,4424,4433,4439,4445],{},[14,4405,4406,4407,4410,4411,4413,4414,4417],{},"анализ структур: ",[18,4408,4409],{},"поля"," (NumField, Field), ",[18,4412,2479],{}," (NumMethod, Method), ",[18,4415,4416],{},"параметры"," (NumIn, NumOut)",[14,4419,4420,4423],{},[18,4421,4422],{},"создание"," типов: структуры, массивы, указатели, каналы — всё через reflect",[14,4425,4426,4429,4430],{},[18,4427,4428],{},"вызов"," функций и методов: ",[65,4431,4432],{},"MethodByName(\"Add\").Call(args)",[14,4434,4435,4438],{},[18,4436,4437],{},"проверки",": тип реализует интерфейс (Implements), тип comparable",[14,4440,4441,4444],{},[18,4442,4443],{},"каналы и select"," через рефлексию: Send, Recv, Select с кейсами",[14,4446,4447,4448,4450,4451],{},"nil → ",[65,4449,3881],{}," с Kind == ",[65,4452,4453],{},"Invalid",[42,4455],{},[50,4457,4459],{"id":4458},"reflect-api-на-практике","reflect API на практике",[50,4461,4463],{"id":4462},"анализ-структур","Анализ структур",[59,4465,4467],{"className":61,"code":4466,"language":63,"meta":5,"style":5},"type User struct {\n    Name string `json:\"name\"`\n    Age  int    `json:\"age\"`\n}\nfunc (u User) Greet() string { return \"Hi, \" + u.Name }\n\nt := reflect.TypeOf(User{})\n\nt.Kind()                    \u002F\u002F struct\nt.NumField()                \u002F\u002F 2\nt.Field(0).Name             \u002F\u002F \"Name\"\nt.Field(0).Type.String()    \u002F\u002F \"string\"\nt.NumMethod()               \u002F\u002F 1\nt.Method(0).Name            \u002F\u002F \"Greet\"\nt.Method(0).Type.NumIn()    \u002F\u002F 1 (ресивер)\nt.Method(0).Type.NumOut()   \u002F\u002F 1\n",[65,4468,4469,4480,4490,4500,4504,4538,4542,4559,4563,4577,4590,4607,4629,4642,4659,4679],{"__ignoreMap":5},[68,4470,4471,4473,4476,4478],{"class":70,"line":71},[68,4472,493],{"class":81},[68,4474,4475],{"class":85}," User",[68,4477,1604],{"class":81},[68,4479,112],{"class":89},[68,4481,4482,4485,4487],{"class":70,"line":78},[68,4483,4484],{"class":89},"    Name ",[68,4486,576],{"class":81},[68,4488,4489],{"class":1157}," `json:\"name\"`\n",[68,4491,4492,4495,4497],{"class":70,"line":115},[68,4493,4494],{"class":89},"    Age  ",[68,4496,109],{"class":81},[68,4498,4499],{"class":1157},"    `json:\"age\"`\n",[68,4501,4502],{"class":70,"line":136},[68,4503,148],{"class":89},[68,4505,4506,4508,4510,4513,4516,4518,4521,4523,4525,4527,4529,4532,4535],{"class":70,"line":145},[68,4507,82],{"class":81},[68,4509,1623],{"class":89},[68,4511,4512],{"class":93},"u ",[68,4514,4515],{"class":85},"User",[68,4517,106],{"class":89},[68,4519,4520],{"class":85},"Greet",[68,4522,573],{"class":89},[68,4524,576],{"class":81},[68,4526,381],{"class":89},[68,4528,130],{"class":81},[68,4530,4531],{"class":1157}," \"Hi, \"",[68,4533,4534],{"class":81}," +",[68,4536,4537],{"class":89}," u.Name }\n",[68,4539,4540],{"class":70,"line":151},[68,4541,155],{"emptyLinePlaceholder":154},[68,4543,4544,4546,4548,4550,4552,4554,4556],{"class":70,"line":158},[68,4545,3836],{"class":89},[68,4547,2754],{"class":81},[68,4549,3841],{"class":89},[68,4551,3748],{"class":85},[68,4553,90],{"class":89},[68,4555,4515],{"class":85},[68,4557,4558],{"class":89},"{})\n",[68,4560,4561],{"class":70,"line":184},[68,4562,155],{"emptyLinePlaceholder":154},[68,4564,4565,4568,4571,4574],{"class":70,"line":199},[68,4566,4567],{"class":89},"t.",[68,4569,4570],{"class":85},"Kind",[68,4572,4573],{"class":89},"()                    ",[68,4575,4576],{"class":74},"\u002F\u002F struct\n",[68,4578,4579,4581,4584,4587],{"class":70,"line":206},[68,4580,4567],{"class":89},[68,4582,4583],{"class":85},"NumField",[68,4585,4586],{"class":89},"()                ",[68,4588,4589],{"class":74},"\u002F\u002F 2\n",[68,4591,4592,4594,4597,4599,4601,4604],{"class":70,"line":2425},[68,4593,4567],{"class":89},[68,4595,4596],{"class":85},"Field",[68,4598,90],{"class":89},[68,4600,2151],{"class":302},[68,4602,4603],{"class":89},").Name             ",[68,4605,4606],{"class":74},"\u002F\u002F \"Name\"\n",[68,4608,4609,4611,4613,4615,4617,4620,4623,4626],{"class":70,"line":2437},[68,4610,4567],{"class":89},[68,4612,4596],{"class":85},[68,4614,90],{"class":89},[68,4616,2151],{"class":302},[68,4618,4619],{"class":89},").Type.",[68,4621,4622],{"class":85},"String",[68,4624,4625],{"class":89},"()    ",[68,4627,4628],{"class":74},"\u002F\u002F \"string\"\n",[68,4630,4631,4633,4636,4639],{"class":70,"line":2449},[68,4632,4567],{"class":89},[68,4634,4635],{"class":85},"NumMethod",[68,4637,4638],{"class":89},"()               ",[68,4640,4641],{"class":74},"\u002F\u002F 1\n",[68,4643,4644,4646,4649,4651,4653,4656],{"class":70,"line":2687},[68,4645,4567],{"class":89},[68,4647,4648],{"class":85},"Method",[68,4650,90],{"class":89},[68,4652,2151],{"class":302},[68,4654,4655],{"class":89},").Name            ",[68,4657,4658],{"class":74},"\u002F\u002F \"Greet\"\n",[68,4660,4661,4663,4665,4667,4669,4671,4674,4676],{"class":70,"line":2693},[68,4662,4567],{"class":89},[68,4664,4648],{"class":85},[68,4666,90],{"class":89},[68,4668,2151],{"class":302},[68,4670,4619],{"class":89},[68,4672,4673],{"class":85},"NumIn",[68,4675,4625],{"class":89},[68,4677,4678],{"class":74},"\u002F\u002F 1 (ресивер)\n",[68,4680,4681,4683,4685,4687,4689,4691,4694,4697],{"class":70,"line":2722},[68,4682,4567],{"class":89},[68,4684,4648],{"class":85},[68,4686,90],{"class":89},[68,4688,2151],{"class":302},[68,4690,4619],{"class":89},[68,4692,4693],{"class":85},"NumOut",[68,4695,4696],{"class":89},"()   ",[68,4698,4641],{"class":74},[339,4700,4701,4702,4705],{},"Для метода ",[65,4703,4704],{},"NumIn()"," возвращает количество входных параметров включая ресивер.",[50,4707,4709],{"id":4708},"создание-типов","Создание типов",[59,4711,4713],{"className":61,"code":4712,"language":63,"meta":5,"style":5},"\u002F\u002F Структура\nfields := []reflect.StructField{\n    {Name: \"X\", Type: reflect.TypeOf(0)},\n    {Name: \"Y\", Type: reflect.TypeOf(\"\")},\n}\nstructType := reflect.StructOf(fields)\n\n\u002F\u002F Массив\narrayType := reflect.ArrayOf(5, reflect.TypeOf(0))\n\n\u002F\u002F Указатель\nptrType := reflect.PointerTo(reflect.TypeOf(0))\n",[65,4714,4715,4720,4739,4759,4777,4781,4796,4800,4805,4834,4838,4843],{"__ignoreMap":5},[68,4716,4717],{"class":70,"line":71},[68,4718,4719],{"class":74},"\u002F\u002F Структура\n",[68,4721,4722,4725,4727,4729,4731,4733,4736],{"class":70,"line":78},[68,4723,4724],{"class":89},"fields ",[68,4726,2754],{"class":81},[68,4728,2127],{"class":89},[68,4730,3795],{"class":85},[68,4732,587],{"class":89},[68,4734,4735],{"class":85},"StructField",[68,4737,4738],{"class":89},"{\n",[68,4740,4741,4744,4747,4750,4752,4754,4756],{"class":70,"line":115},[68,4742,4743],{"class":89},"    {Name: ",[68,4745,4746],{"class":1157},"\"X\"",[68,4748,4749],{"class":89},", Type: reflect.",[68,4751,3748],{"class":85},[68,4753,90],{"class":89},[68,4755,2151],{"class":302},[68,4757,4758],{"class":89},")},\n",[68,4760,4761,4763,4766,4768,4770,4772,4775],{"class":70,"line":136},[68,4762,4743],{"class":89},[68,4764,4765],{"class":1157},"\"Y\"",[68,4767,4749],{"class":89},[68,4769,3748],{"class":85},[68,4771,90],{"class":89},[68,4773,4774],{"class":1157},"\"\"",[68,4776,4758],{"class":89},[68,4778,4779],{"class":70,"line":145},[68,4780,148],{"class":89},[68,4782,4783,4786,4788,4790,4793],{"class":70,"line":151},[68,4784,4785],{"class":89},"structType ",[68,4787,2754],{"class":81},[68,4789,3841],{"class":89},[68,4791,4792],{"class":85},"StructOf",[68,4794,4795],{"class":89},"(fields)\n",[68,4797,4798],{"class":70,"line":158},[68,4799,155],{"emptyLinePlaceholder":154},[68,4801,4802],{"class":70,"line":184},[68,4803,4804],{"class":74},"\u002F\u002F Массив\n",[68,4806,4807,4810,4812,4814,4817,4819,4822,4825,4827,4829,4831],{"class":70,"line":199},[68,4808,4809],{"class":89},"arrayType ",[68,4811,2754],{"class":81},[68,4813,3841],{"class":89},[68,4815,4816],{"class":85},"ArrayOf",[68,4818,90],{"class":89},[68,4820,4821],{"class":302},"5",[68,4823,4824],{"class":89},", reflect.",[68,4826,3748],{"class":85},[68,4828,90],{"class":89},[68,4830,2151],{"class":302},[68,4832,4833],{"class":89},"))\n",[68,4835,4836],{"class":70,"line":206},[68,4837,155],{"emptyLinePlaceholder":154},[68,4839,4840],{"class":70,"line":2425},[68,4841,4842],{"class":74},"\u002F\u002F Указатель\n",[68,4844,4845,4848,4850,4852,4855,4858,4860,4862,4864],{"class":70,"line":2437},[68,4846,4847],{"class":89},"ptrType ",[68,4849,2754],{"class":81},[68,4851,3841],{"class":89},[68,4853,4854],{"class":85},"PointerTo",[68,4856,4857],{"class":89},"(reflect.",[68,4859,3748],{"class":85},[68,4861,90],{"class":89},[68,4863,2151],{"class":302},[68,4865,4833],{"class":89},[339,4867,4868,4869,4872],{},"Каналы создаются через ",[65,4870,4871],{},"reflect.MakeChan"," с указанием направления и буфера.",[50,4874,4876],{"id":4875},"вызов-методов-и-функций","Вызов методов и функций",[59,4878,4880],{"className":61,"code":4879,"language":63,"meta":5,"style":5},"package main\n\nimport (\n    \"fmt\"\n    \"reflect\"\n)\n\ntype Vec struct{ X, Y int }\n\nfunc (v Vec) Add(other Vec) Vec { return Vec{v.X + other.X, v.Y + other.Y} }\n\nfunc main() {\n    v := reflect.ValueOf(Vec{1, 2})\n    method := v.MethodByName(\"Add\")\n    args := []reflect.Value{reflect.ValueOf(Vec{3, 4})}\n    result := method.Call(args)\n    fmt.Println(result[0]) \u002F\u002F {4 6}\n\n    \u002F\u002F Вызов обычной функции\n    fn := reflect.ValueOf(fmt.Sprintf)\n    res := fn.Call([]reflect.Value{\n        reflect.ValueOf(\"hello %s\"),\n        reflect.ValueOf(\"world\"),\n    })\n    fmt.Println(res[0])\n}\n",[65,4881,4882,4888,4892,4898,4906,4914,4918,4922,4938,4942,4987,4991,4999,5025,5044,5081,5097,5113,5117,5122,5136,5159,5181,5195,5201,5216],{"__ignoreMap":5},[68,4883,4884,4886],{"class":70,"line":71},[68,4885,3895],{"class":81},[68,4887,3898],{"class":85},[68,4889,4890],{"class":70,"line":78},[68,4891,155],{"emptyLinePlaceholder":154},[68,4893,4894,4896],{"class":70,"line":115},[68,4895,3907],{"class":81},[68,4897,3910],{"class":89},[68,4899,4900,4902,4904],{"class":70,"line":136},[68,4901,3915],{"class":1157},[68,4903,3918],{"class":85},[68,4905,3921],{"class":1157},[68,4907,4908,4910,4912],{"class":70,"line":145},[68,4909,3915],{"class":1157},[68,4911,3795],{"class":85},[68,4913,3921],{"class":1157},[68,4915,4916],{"class":70,"line":151},[68,4917,2781],{"class":89},[68,4919,4920],{"class":70,"line":158},[68,4921,155],{"emptyLinePlaceholder":154},[68,4923,4924,4926,4929,4931,4934,4936],{"class":70,"line":184},[68,4925,493],{"class":81},[68,4927,4928],{"class":85}," Vec",[68,4930,1604],{"class":81},[68,4932,4933],{"class":89},"{ X, Y ",[68,4935,109],{"class":81},[68,4937,999],{"class":89},[68,4939,4940],{"class":70,"line":199},[68,4941,155],{"emptyLinePlaceholder":154},[68,4943,4944,4946,4948,4950,4953,4955,4957,4959,4962,4964,4966,4968,4970,4972,4974,4977,4979,4982,4984],{"class":70,"line":206},[68,4945,82],{"class":81},[68,4947,1623],{"class":89},[68,4949,3854],{"class":93},[68,4951,4952],{"class":85},"Vec",[68,4954,106],{"class":89},[68,4956,2656],{"class":85},[68,4958,90],{"class":89},[68,4960,4961],{"class":93},"other",[68,4963,4928],{"class":85},[68,4965,106],{"class":89},[68,4967,4952],{"class":85},[68,4969,381],{"class":89},[68,4971,130],{"class":81},[68,4973,4928],{"class":85},[68,4975,4976],{"class":89},"{v.X ",[68,4978,829],{"class":81},[68,4980,4981],{"class":89}," other.X, v.Y ",[68,4983,829],{"class":81},[68,4985,4986],{"class":89}," other.Y} }\n",[68,4988,4989],{"class":70,"line":2425},[68,4990,155],{"emptyLinePlaceholder":154},[68,4992,4993,4995,4997],{"class":70,"line":2437},[68,4994,82],{"class":81},[68,4996,3944],{"class":85},[68,4998,3947],{"class":89},[68,5000,5001,5003,5005,5007,5009,5011,5013,5016,5018,5020,5022],{"class":70,"line":2449},[68,5002,3964],{"class":89},[68,5004,2754],{"class":81},[68,5006,3841],{"class":89},[68,5008,3751],{"class":85},[68,5010,90],{"class":89},[68,5012,4952],{"class":85},[68,5014,5015],{"class":89},"{",[68,5017,303],{"class":302},[68,5019,97],{"class":89},[68,5021,308],{"class":302},[68,5023,5024],{"class":89},"})\n",[68,5026,5027,5030,5032,5034,5037,5039,5042],{"class":70,"line":2687},[68,5028,5029],{"class":89},"    method ",[68,5031,2754],{"class":81},[68,5033,3992],{"class":89},[68,5035,5036],{"class":85},"MethodByName",[68,5038,90],{"class":89},[68,5040,5041],{"class":1157},"\"Add\"",[68,5043,2781],{"class":89},[68,5045,5046,5049,5051,5053,5055,5057,5060,5063,5065,5067,5069,5071,5073,5075,5078],{"class":70,"line":2693},[68,5047,5048],{"class":89},"    args ",[68,5050,2754],{"class":81},[68,5052,2127],{"class":89},[68,5054,3795],{"class":85},[68,5056,587],{"class":89},[68,5058,5059],{"class":85},"Value",[68,5061,5062],{"class":89},"{reflect.",[68,5064,3751],{"class":85},[68,5066,90],{"class":89},[68,5068,4952],{"class":85},[68,5070,5015],{"class":89},[68,5072,3165],{"class":302},[68,5074,97],{"class":89},[68,5076,5077],{"class":302},"4",[68,5079,5080],{"class":89},"})}\n",[68,5082,5083,5086,5088,5091,5094],{"class":70,"line":2722},[68,5084,5085],{"class":89},"    result ",[68,5087,2754],{"class":81},[68,5089,5090],{"class":89}," method.",[68,5092,5093],{"class":85},"Call",[68,5095,5096],{"class":89},"(args)\n",[68,5098,5099,5101,5103,5106,5108,5110],{"class":70,"line":2733},[68,5100,4007],{"class":89},[68,5102,3136],{"class":85},[68,5104,5105],{"class":89},"(result[",[68,5107,2151],{"class":302},[68,5109,2653],{"class":89},[68,5111,5112],{"class":74},"\u002F\u002F {4 6}\n",[68,5114,5115],{"class":70,"line":2738},[68,5116,155],{"emptyLinePlaceholder":154},[68,5118,5119],{"class":70,"line":2743},[68,5120,5121],{"class":74},"    \u002F\u002F Вызов обычной функции\n",[68,5123,5124,5127,5129,5131,5133],{"class":70,"line":2749},[68,5125,5126],{"class":89},"    fn ",[68,5128,2754],{"class":81},[68,5130,3841],{"class":89},[68,5132,3751],{"class":85},[68,5134,5135],{"class":89},"(fmt.Sprintf)\n",[68,5137,5138,5141,5143,5146,5148,5151,5153,5155,5157],{"class":70,"line":2769},[68,5139,5140],{"class":89},"    res ",[68,5142,2754],{"class":81},[68,5144,5145],{"class":89}," fn.",[68,5147,5093],{"class":85},[68,5149,5150],{"class":89},"([]",[68,5152,3795],{"class":85},[68,5154,587],{"class":89},[68,5156,5059],{"class":85},[68,5158,4738],{"class":89},[68,5160,5162,5165,5167,5169,5172,5175,5178],{"class":70,"line":5161},22,[68,5163,5164],{"class":89},"        reflect.",[68,5166,3751],{"class":85},[68,5168,90],{"class":89},[68,5170,5171],{"class":1157},"\"hello ",[68,5173,5174],{"class":302},"%s",[68,5176,5177],{"class":1157},"\"",[68,5179,5180],{"class":89},"),\n",[68,5182,5184,5186,5188,5190,5193],{"class":70,"line":5183},23,[68,5185,5164],{"class":89},[68,5187,3751],{"class":85},[68,5189,90],{"class":89},[68,5191,5192],{"class":1157},"\"world\"",[68,5194,5180],{"class":89},[68,5196,5198],{"class":70,"line":5197},24,[68,5199,5200],{"class":89},"    })\n",[68,5202,5204,5206,5208,5211,5213],{"class":70,"line":5203},25,[68,5205,4007],{"class":89},[68,5207,3136],{"class":85},[68,5209,5210],{"class":89},"(res[",[68,5212,2151],{"class":302},[68,5214,5215],{"class":89},"])\n",[68,5217,5219],{"class":70,"line":5218},26,[68,5220,148],{"class":89},[339,5222,5223,5225,5226,5228],{},[65,5224,5036],{}," принимает имя метода как строку, возвращает ",[65,5227,3881],{}," типа функции. Ресивер уже связан — в args передаём только остальные аргументы.",[50,5230,5232],{"id":5231},"проверка-implements","Проверка implements",[59,5234,5236],{"className":61,"code":5235,"language":63,"meta":5,"style":5},"type Stringer interface{ String() string }\n\ndataType := reflect.TypeOf(Data{})\nstringerType := reflect.TypeOf((*Stringer)(nil)).Elem()\n\ndataType.Implements(stringerType)  \u002F\u002F true\u002Ffalse\n",[65,5237,5238,5257,5261,5279,5310,5314],{"__ignoreMap":5},[68,5239,5240,5242,5245,5247,5249,5251,5253,5255],{"class":70,"line":71},[68,5241,493],{"class":81},[68,5243,5244],{"class":85}," Stringer",[68,5246,499],{"class":81},[68,5248,856],{"class":89},[68,5250,4622],{"class":85},[68,5252,573],{"class":89},[68,5254,576],{"class":81},[68,5256,999],{"class":89},[68,5258,5259],{"class":70,"line":78},[68,5260,155],{"emptyLinePlaceholder":154},[68,5262,5263,5266,5268,5270,5272,5274,5277],{"class":70,"line":115},[68,5264,5265],{"class":89},"dataType ",[68,5267,2754],{"class":81},[68,5269,3841],{"class":89},[68,5271,3748],{"class":85},[68,5273,90],{"class":89},[68,5275,5276],{"class":85},"Data",[68,5278,4558],{"class":89},[68,5280,5281,5284,5286,5288,5290,5293,5295,5297,5300,5303,5306,5308],{"class":70,"line":136},[68,5282,5283],{"class":89},"stringerType ",[68,5285,2754],{"class":81},[68,5287,3841],{"class":89},[68,5289,3748],{"class":85},[68,5291,5292],{"class":89},"((",[68,5294,1192],{"class":81},[68,5296,590],{"class":85},[68,5298,5299],{"class":89},")(",[68,5301,5302],{"class":302},"nil",[68,5304,5305],{"class":89},")).",[68,5307,4180],{"class":85},[68,5309,4183],{"class":89},[68,5311,5312],{"class":70,"line":145},[68,5313,155],{"emptyLinePlaceholder":154},[68,5315,5316,5319,5322,5325],{"class":70,"line":151},[68,5317,5318],{"class":89},"dataType.",[68,5320,5321],{"class":85},"Implements",[68,5323,5324],{"class":89},"(stringerType)  ",[68,5326,5327],{"class":74},"\u002F\u002F true\u002Ffalse\n",[339,5329,5330],{},"Nil нужен только для получения reflect.Type интерфейса — не создаём реальный объект.",[50,5332,5334],{"id":5333},"каналы-и-select","Каналы и select",[59,5336,5338],{"className":61,"code":5337,"language":63,"meta":5,"style":5},"ch := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(0)), 1)\nch.Send(reflect.ValueOf(42))\nval, ok := ch.TryRecv()\n\n\u002F\u002F Select\ncases := []reflect.SelectCase{\n    {Dir: reflect.SelectRecv, Chan: ch},\n    {Dir: reflect.SelectDefault},\n}\nchosen, value, _ := reflect.Select(cases)\n",[65,5339,5340,5373,5391,5406,5410,5415,5433,5438,5443,5447],{"__ignoreMap":5},[68,5341,5342,5345,5347,5349,5352,5354,5357,5360,5362,5364,5366,5369,5371],{"class":70,"line":71},[68,5343,5344],{"class":89},"ch ",[68,5346,2754],{"class":81},[68,5348,3841],{"class":89},[68,5350,5351],{"class":85},"MakeChan",[68,5353,4857],{"class":89},[68,5355,5356],{"class":85},"ChanOf",[68,5358,5359],{"class":89},"(reflect.BothDir, reflect.",[68,5361,3748],{"class":85},[68,5363,90],{"class":89},[68,5365,2151],{"class":302},[68,5367,5368],{"class":89},")), ",[68,5370,303],{"class":302},[68,5372,2781],{"class":89},[68,5374,5375,5378,5381,5383,5385,5387,5389],{"class":70,"line":78},[68,5376,5377],{"class":89},"ch.",[68,5379,5380],{"class":85},"Send",[68,5382,4857],{"class":89},[68,5384,3751],{"class":85},[68,5386,90],{"class":89},[68,5388,1334],{"class":302},[68,5390,4833],{"class":89},[68,5392,5393,5396,5398,5401,5404],{"class":70,"line":115},[68,5394,5395],{"class":89},"val, ok ",[68,5397,2754],{"class":81},[68,5399,5400],{"class":89}," ch.",[68,5402,5403],{"class":85},"TryRecv",[68,5405,4183],{"class":89},[68,5407,5408],{"class":70,"line":136},[68,5409,155],{"emptyLinePlaceholder":154},[68,5411,5412],{"class":70,"line":145},[68,5413,5414],{"class":74},"\u002F\u002F Select\n",[68,5416,5417,5420,5422,5424,5426,5428,5431],{"class":70,"line":151},[68,5418,5419],{"class":89},"cases ",[68,5421,2754],{"class":81},[68,5423,2127],{"class":89},[68,5425,3795],{"class":85},[68,5427,587],{"class":89},[68,5429,5430],{"class":85},"SelectCase",[68,5432,4738],{"class":89},[68,5434,5435],{"class":70,"line":158},[68,5436,5437],{"class":89},"    {Dir: reflect.SelectRecv, Chan: ch},\n",[68,5439,5440],{"class":70,"line":184},[68,5441,5442],{"class":89},"    {Dir: reflect.SelectDefault},\n",[68,5444,5445],{"class":70,"line":199},[68,5446,148],{"class":89},[68,5448,5449,5452,5454,5456,5459],{"class":70,"line":206},[68,5450,5451],{"class":89},"chosen, value, _ ",[68,5453,2754],{"class":81},[68,5455,3841],{"class":89},[68,5457,5458],{"class":85},"Select",[68,5460,5461],{"class":89},"(cases)\n",[339,5463,5464,5467,5468,5470],{},[65,5465,5466],{},"reflect.Select"," принимает срез ",[65,5469,5430],{}," — это позволяет делать select с динамическим количеством каналов, что невозможно через обычный select.",[50,5472,5474],{"id":5473},"nil-и-invalid","Nil и Invalid",[59,5476,5479],{"className":61,"code":5477,"language":63,"meta":5478,"style":5},"v := reflect.ValueOf(nil)\nfmt.Println(v.IsValid())  \u002F\u002F false\nfmt.Println(v.Kind())     \u002F\u002F invalid\n\n\u002F\u002F Элемент nil-среза\ns := reflect.ValueOf([]int(nil))\nelem := s.Index(0) \u002F\u002F паника!\n_ = elem\n","no-run",[65,5480,5481,5497,5513,5529,5533,5538,5558,5580],{"__ignoreMap":5},[68,5482,5483,5485,5487,5489,5491,5493,5495],{"class":70,"line":71},[68,5484,3854],{"class":89},[68,5486,2754],{"class":81},[68,5488,3841],{"class":89},[68,5490,3751],{"class":85},[68,5492,90],{"class":89},[68,5494,5302],{"class":302},[68,5496,2781],{"class":89},[68,5498,5499,5501,5503,5505,5508,5511],{"class":70,"line":78},[68,5500,4074],{"class":89},[68,5502,3136],{"class":85},[68,5504,4079],{"class":89},[68,5506,5507],{"class":85},"IsValid",[68,5509,5510],{"class":89},"())  ",[68,5512,4088],{"class":74},[68,5514,5515,5517,5519,5521,5523,5526],{"class":70,"line":115},[68,5516,4074],{"class":89},[68,5518,3136],{"class":85},[68,5520,4079],{"class":89},[68,5522,4570],{"class":85},[68,5524,5525],{"class":89},"())     ",[68,5527,5528],{"class":74},"\u002F\u002F invalid\n",[68,5530,5531],{"class":70,"line":136},[68,5532,155],{"emptyLinePlaceholder":154},[68,5534,5535],{"class":70,"line":145},[68,5536,5537],{"class":74},"\u002F\u002F Элемент nil-среза\n",[68,5539,5540,5542,5544,5546,5548,5550,5552,5554,5556],{"class":70,"line":151},[68,5541,1626],{"class":89},[68,5543,2754],{"class":81},[68,5545,3841],{"class":89},[68,5547,3751],{"class":85},[68,5549,5150],{"class":89},[68,5551,109],{"class":81},[68,5553,90],{"class":89},[68,5555,5302],{"class":302},[68,5557,4833],{"class":89},[68,5559,5560,5563,5565,5568,5571,5573,5575,5577],{"class":70,"line":158},[68,5561,5562],{"class":89},"elem ",[68,5564,2754],{"class":81},[68,5566,5567],{"class":89}," s.",[68,5569,5570],{"class":85},"Index",[68,5572,90],{"class":89},[68,5574,2151],{"class":302},[68,5576,106],{"class":89},[68,5578,5579],{"class":74},"\u002F\u002F паника!\n",[68,5581,5582,5585,5587],{"class":70,"line":184},[68,5583,5584],{"class":89},"_ ",[68,5586,1699],{"class":81},[68,5588,5589],{"class":89}," elem\n",[339,5591,5592,5595],{},[65,5593,5594],{},"IsValid()"," возвращает false если Value — нулевое значение (создано из nil или дефолтным конструктором). Вызов любого метода на невалидном Value кроме IsValid, Kind, String — паника.",[42,5597],{},[11,5599,5600,5606,5612,5618,5624,5630],{},[14,5601,5602,5605],{},[18,5603,5604],{},"сериализация\u002Fдесериализация",": encoding\u002Fjson, encoding\u002Fxml — теги + рефлексия",[14,5607,5608,5611],{},[18,5609,5610],{},"валидаторы",": проверка полей по тегам (go-playground\u002Fvalidator, 17k+ stars)",[14,5613,5614,5617],{},[18,5615,5616],{},"ORM",": маппинг структур на таблицы, автоматический scan",[14,5619,5620,5623],{},[18,5621,5622],{},"DI-контейнеры",": внедрение зависимостей по типу",[14,5625,5626,5629],{},[18,5627,5628],{},"дженерики + рефлексия"," вместе: обобщённый код на двух уровнях",[14,5631,5632,5635],{},[18,5633,5634],{},"изменение приватных полей",": unsafe.Pointer + reflect (крайний случай)",[42,5637],{},[50,5639,5641],{"id":5640},"кейсы-reflect","Кейсы reflect",[50,5643,5645],{"id":5644},"сериализация-главный-кейс","Сериализация — главный кейс",[59,5647,5649],{"className":61,"code":5648,"language":63,"meta":5,"style":5},"type User struct {\n    Name string `json:\"name\"`\n    Age  int    `json:\"age,omitempty\"`\n}\n\n\u002F\u002F encoding\u002Fjson внутри:\n\u002F\u002F 1. reflect.TypeOf(user) → перебрать поля\n\u002F\u002F 2. field.Tag.Get(\"json\") → получить имя в JSON\n\u002F\u002F 3. reflect.ValueOf(user).Field(i) → получить значение\n\u002F\u002F 4. собрать JSON\n\ndata, _ := json.Marshal(User{Name: \"Alice\", Age: 30})\n\u002F\u002F {\"name\":\"Alice\",\"age\":30}\n",[65,5650,5651,5661,5669,5678,5682,5686,5691,5696,5701,5706,5711,5715,5746],{"__ignoreMap":5},[68,5652,5653,5655,5657,5659],{"class":70,"line":71},[68,5654,493],{"class":81},[68,5656,4475],{"class":85},[68,5658,1604],{"class":81},[68,5660,112],{"class":89},[68,5662,5663,5665,5667],{"class":70,"line":78},[68,5664,4484],{"class":89},[68,5666,576],{"class":81},[68,5668,4489],{"class":1157},[68,5670,5671,5673,5675],{"class":70,"line":115},[68,5672,4494],{"class":89},[68,5674,109],{"class":81},[68,5676,5677],{"class":1157},"    `json:\"age,omitempty\"`\n",[68,5679,5680],{"class":70,"line":136},[68,5681,148],{"class":89},[68,5683,5684],{"class":70,"line":145},[68,5685,155],{"emptyLinePlaceholder":154},[68,5687,5688],{"class":70,"line":151},[68,5689,5690],{"class":74},"\u002F\u002F encoding\u002Fjson внутри:\n",[68,5692,5693],{"class":70,"line":158},[68,5694,5695],{"class":74},"\u002F\u002F 1. reflect.TypeOf(user) → перебрать поля\n",[68,5697,5698],{"class":70,"line":184},[68,5699,5700],{"class":74},"\u002F\u002F 2. field.Tag.Get(\"json\") → получить имя в JSON\n",[68,5702,5703],{"class":70,"line":199},[68,5704,5705],{"class":74},"\u002F\u002F 3. reflect.ValueOf(user).Field(i) → получить значение\n",[68,5707,5708],{"class":70,"line":206},[68,5709,5710],{"class":74},"\u002F\u002F 4. собрать JSON\n",[68,5712,5713],{"class":70,"line":2425},[68,5714,155],{"emptyLinePlaceholder":154},[68,5716,5717,5720,5722,5725,5728,5730,5732,5735,5738,5741,5744],{"class":70,"line":2437},[68,5718,5719],{"class":89},"data, _ ",[68,5721,2754],{"class":81},[68,5723,5724],{"class":89}," json.",[68,5726,5727],{"class":85},"Marshal",[68,5729,90],{"class":89},[68,5731,4515],{"class":85},[68,5733,5734],{"class":89},"{Name: ",[68,5736,5737],{"class":1157},"\"Alice\"",[68,5739,5740],{"class":89},", Age: ",[68,5742,5743],{"class":302},"30",[68,5745,5024],{"class":89},[68,5747,5748],{"class":70,"line":2449},[68,5749,5750],{"class":74},"\u002F\u002F {\"name\":\"Alice\",\"age\":30}\n",[339,5752,5753,5756],{},[65,5754,5755],{},"encoding\u002Fjson"," использует рефлексию для перебора полей структуры, чтения тегов и получения значений. Без рефлексии пришлось бы для каждой структуры писать явную сериализацию.",[50,5758,5759],{"id":5610},"Валидаторы",[59,5761,5763],{"className":61,"code":5762,"language":63,"meta":5,"style":5},"type CreateUser struct {\n    Email string `validate:\"required,email\"`\n    Age   int    `validate:\"gte=18,lte=120\"`\n}\n\n\u002F\u002F Библиотека validator:\n\u002F\u002F 1. reflect → перебрать поля\n\u002F\u002F 2. прочитать тег validate\n\u002F\u002F 3. распарсить правила\n\u002F\u002F 4. проверить значение каждого поля\n",[65,5764,5765,5776,5786,5796,5800,5804,5809,5814,5819,5824],{"__ignoreMap":5},[68,5766,5767,5769,5772,5774],{"class":70,"line":71},[68,5768,493],{"class":81},[68,5770,5771],{"class":85}," CreateUser",[68,5773,1604],{"class":81},[68,5775,112],{"class":89},[68,5777,5778,5781,5783],{"class":70,"line":78},[68,5779,5780],{"class":89},"    Email ",[68,5782,576],{"class":81},[68,5784,5785],{"class":1157}," `validate:\"required,email\"`\n",[68,5787,5788,5791,5793],{"class":70,"line":115},[68,5789,5790],{"class":89},"    Age   ",[68,5792,109],{"class":81},[68,5794,5795],{"class":1157},"    `validate:\"gte=18,lte=120\"`\n",[68,5797,5798],{"class":70,"line":136},[68,5799,148],{"class":89},[68,5801,5802],{"class":70,"line":145},[68,5803,155],{"emptyLinePlaceholder":154},[68,5805,5806],{"class":70,"line":151},[68,5807,5808],{"class":74},"\u002F\u002F Библиотека validator:\n",[68,5810,5811],{"class":70,"line":158},[68,5812,5813],{"class":74},"\u002F\u002F 1. reflect → перебрать поля\n",[68,5815,5816],{"class":70,"line":184},[68,5817,5818],{"class":74},"\u002F\u002F 2. прочитать тег validate\n",[68,5820,5821],{"class":70,"line":199},[68,5822,5823],{"class":74},"\u002F\u002F 3. распарсить правила\n",[68,5825,5826],{"class":70,"line":206},[68,5827,5828],{"class":74},"\u002F\u002F 4. проверить значение каждого поля\n",[339,5830,5831],{},"Примеры популярных библиотек: go-playground\u002Fvalidator (17k+ stars), swagger (10k+ stars). Оба используют рефлексию для чтения тегов и значений полей.",[50,5833,5616],{"id":5834},"orm",[339,5836,5837],{},"ORM-библиотеки (gorm, sqlx и др.) используют рефлексию для маппинга полей структур на колонки таблиц и автоматического scan результатов запроса в Go-структуры.",[50,5839,5622],{"id":5840},"di-контейнеры",[339,5842,5843],{},"DI-контейнеры используют рефлексию для анализа типов зависимостей функций-конструкторов и автоматического внедрения зарегистрированных зависимостей по типу.",[50,5845,5847],{"id":5846},"обобщённый-код-в-рантайме","Обобщённый код в рантайме",[59,5849,5851],{"className":61,"code":5850,"language":63,"meta":5,"style":5},"\u002F\u002F Функция bind — привязывает обобщённую реализацию к конкретному типу\n\u002F\u002F Используя рефлексию: анализ типов аргументов → MakeFunc → подмена\n\nfunc invertSlice(s any) any {\n    \u002F\u002F рефлексия: определить тип элемента, развернуть срез\n}\n\nvar invertInts func([]int) []int\nbind(&invertInts, invertSlice)  \u002F\u002F привязка через рефлексию\n\ninvertInts([]int{1, 2, 3})  \u002F\u002F [3, 2, 1]\n",[65,5852,5853,5858,5863,5867,5886,5891,5895,5899,5917,5932,5936],{"__ignoreMap":5},[68,5854,5855],{"class":70,"line":71},[68,5856,5857],{"class":74},"\u002F\u002F Функция bind — привязывает обобщённую реализацию к конкретному типу\n",[68,5859,5860],{"class":70,"line":78},[68,5861,5862],{"class":74},"\u002F\u002F Используя рефлексию: анализ типов аргументов → MakeFunc → подмена\n",[68,5864,5865],{"class":70,"line":115},[68,5866,155],{"emptyLinePlaceholder":154},[68,5868,5869,5871,5874,5876,5878,5880,5882,5884],{"class":70,"line":136},[68,5870,82],{"class":81},[68,5872,5873],{"class":85}," invertSlice",[68,5875,90],{"class":89},[68,5877,1677],{"class":93},[68,5879,373],{"class":85},[68,5881,106],{"class":89},[68,5883,378],{"class":85},[68,5885,112],{"class":89},[68,5887,5888],{"class":70,"line":145},[68,5889,5890],{"class":74},"    \u002F\u002F рефлексия: определить тип элемента, развернуть срез\n",[68,5892,5893],{"class":70,"line":151},[68,5894,148],{"class":89},[68,5896,5897],{"class":70,"line":158},[68,5898,155],{"emptyLinePlaceholder":154},[68,5900,5901,5903,5906,5908,5910,5912,5914],{"class":70,"line":184},[68,5902,1264],{"class":81},[68,5904,5905],{"class":89}," invertInts ",[68,5907,82],{"class":81},[68,5909,5150],{"class":89},[68,5911,109],{"class":81},[68,5913,990],{"class":89},[68,5915,5916],{"class":81},"int\n",[68,5918,5919,5922,5924,5926,5929],{"class":70,"line":199},[68,5920,5921],{"class":85},"bind",[68,5923,90],{"class":89},[68,5925,4131],{"class":81},[68,5927,5928],{"class":89},"invertInts, invertSlice)  ",[68,5930,5931],{"class":74},"\u002F\u002F привязка через рефлексию\n",[68,5933,5934],{"class":70,"line":206},[68,5935,155],{"emptyLinePlaceholder":154},[68,5937,5938,5941,5943,5945,5947,5949,5951,5953,5955,5957,5960],{"class":70,"line":2425},[68,5939,5940],{"class":85},"invertInts",[68,5942,5150],{"class":89},[68,5944,109],{"class":81},[68,5946,5015],{"class":89},[68,5948,303],{"class":302},[68,5950,97],{"class":89},[68,5952,308],{"class":302},[68,5954,97],{"class":89},[68,5956,3165],{"class":302},[68,5958,5959],{"class":89},"})  ",[68,5961,5962],{"class":74},"\u002F\u002F [3, 2, 1]\n",[339,5964,5965,5966,587],{},"Метапрограммирование в рантайме: один алгоритм, разные типы — через рефлексию. Ключевой инструмент — ",[65,5967,5968],{},"reflect.MakeFunc",[45,5970,5972],{"id":5971},"дженерики-и-reflect-вместе","Дженерики и reflect вместе",[50,5974,5976],{"id":5975},"дженерики-рефлексия-вместе","Дженерики + рефлексия вместе",[59,5978,5980],{"className":61,"code":5979,"language":63,"meta":5,"style":5},"\u002F\u002F Generic (compile-time) + reflect (runtime)\nfunc AssignPrivateField[T any](obj *T, field string, value any) {\n    v := reflect.ValueOf(obj).Elem()\n    f := v.FieldByName(field)\n    ptr := unsafe.Pointer(f.UnsafeAddr())\n    *(*T)(ptr) = value.(T)  \u002F\u002F ← generic + unsafe\n}\n",[65,5981,5982,5987,6024,6041,6056,6078,6104],{"__ignoreMap":5},[68,5983,5984],{"class":70,"line":71},[68,5985,5986],{"class":74},"\u002F\u002F Generic (compile-time) + reflect (runtime)\n",[68,5988,5989,5991,5994,5996,5998,6000,6002,6005,6007,6009,6011,6014,6016,6018,6020,6022],{"class":70,"line":78},[68,5990,82],{"class":81},[68,5992,5993],{"class":85}," AssignPrivateField",[68,5995,232],{"class":89},[68,5997,235],{"class":93},[68,5999,373],{"class":85},[68,6001,245],{"class":89},[68,6003,6004],{"class":93},"obj",[68,6006,1680],{"class":81},[68,6008,235],{"class":85},[68,6010,97],{"class":89},[68,6012,6013],{"class":93},"field",[68,6015,3489],{"class":81},[68,6017,97],{"class":89},[68,6019,2170],{"class":93},[68,6021,373],{"class":85},[68,6023,1691],{"class":89},[68,6025,6026,6028,6030,6032,6034,6037,6039],{"class":70,"line":115},[68,6027,3964],{"class":89},[68,6029,2754],{"class":81},[68,6031,3841],{"class":89},[68,6033,3751],{"class":85},[68,6035,6036],{"class":89},"(obj).",[68,6038,4180],{"class":85},[68,6040,4183],{"class":89},[68,6042,6043,6046,6048,6050,6053],{"class":70,"line":136},[68,6044,6045],{"class":89},"    f ",[68,6047,2754],{"class":81},[68,6049,3992],{"class":89},[68,6051,6052],{"class":85},"FieldByName",[68,6054,6055],{"class":89},"(field)\n",[68,6057,6058,6061,6063,6066,6069,6072,6075],{"class":70,"line":145},[68,6059,6060],{"class":89},"    ptr ",[68,6062,2754],{"class":81},[68,6064,6065],{"class":89}," unsafe.",[68,6067,6068],{"class":85},"Pointer",[68,6070,6071],{"class":89},"(f.",[68,6073,6074],{"class":85},"UnsafeAddr",[68,6076,6077],{"class":89},"())\n",[68,6079,6080,6083,6085,6087,6089,6092,6094,6097,6099,6101],{"class":70,"line":151},[68,6081,6082],{"class":81},"    *",[68,6084,90],{"class":89},[68,6086,1192],{"class":81},[68,6088,235],{"class":85},[68,6090,6091],{"class":89},")(ptr) ",[68,6093,1699],{"class":81},[68,6095,6096],{"class":89}," value.(",[68,6098,235],{"class":85},[68,6100,1444],{"class":89},[68,6102,6103],{"class":74},"\u002F\u002F ← generic + unsafe\n",[68,6105,6106],{"class":70,"line":158},[68,6107,148],{"class":89},[339,6109,6110,6111,6114,6115,587],{},"Два уровня метапрограммирования в одной функции: дженерики работают на этапе компиляции (type parameters), рефлексия — в рантайме. Для изменения приватных полей требуется ",[65,6112,6113],{},"unsafe.Pointer"," + ",[65,6116,6117],{},"UnsafeAddr()",[42,6119],{},[11,6121,6122,6128,6134,6140,6150],{},[14,6123,6124,6127],{},[18,6125,6126],{},"производительность",": рефлексия существенно медленнее прямого кода",[14,6129,6130,6133],{},[18,6131,6132],{},"сложность",": огромное API (десятки методов), код трудно читать и писать",[14,6135,6136,6139],{},[18,6137,6138],{},"паники в рантайме",": SetFloat на non-settable, Elem на non-pointer, Index на nil-slice",[14,6141,6142,6145,6146,6149],{},[18,6143,6144],{},"GC-ловушка",": ",[65,6147,6148],{},"Value.Pointer()"," возвращает uintptr — GC может собрать объект",[14,6151,6152],{},"ограничения: нельзя создать интерфейсный тип (до 1.22), нельзя создать type definition",[42,6154],{},[50,6156,6158],{"id":6157},"риски-reflect","Риски reflect",[50,6160,6161],{"id":6126},"Производительность",[59,6163,6165],{"className":61,"code":6164,"language":63,"meta":5,"style":5},"\u002F\u002F Прямой вызов\nuser.Name = \"Alice\"\n\n\u002F\u002F Через рефлексию — в разы медленнее\nv := reflect.ValueOf(&user).Elem()\nv.FieldByName(\"Name\").SetString(\"Alice\")\n",[65,6166,6167,6172,6182,6186,6191,6212],{"__ignoreMap":5},[68,6168,6169],{"class":70,"line":71},[68,6170,6171],{"class":74},"\u002F\u002F Прямой вызов\n",[68,6173,6174,6177,6179],{"class":70,"line":78},[68,6175,6176],{"class":89},"user.Name ",[68,6178,1699],{"class":81},[68,6180,6181],{"class":1157}," \"Alice\"\n",[68,6183,6184],{"class":70,"line":115},[68,6185,155],{"emptyLinePlaceholder":154},[68,6187,6188],{"class":70,"line":136},[68,6189,6190],{"class":74},"\u002F\u002F Через рефлексию — в разы медленнее\n",[68,6192,6193,6195,6197,6199,6201,6203,6205,6208,6210],{"class":70,"line":145},[68,6194,3854],{"class":89},[68,6196,2754],{"class":81},[68,6198,3841],{"class":89},[68,6200,3751],{"class":85},[68,6202,90],{"class":89},[68,6204,4131],{"class":81},[68,6206,6207],{"class":89},"user).",[68,6209,4180],{"class":85},[68,6211,4183],{"class":89},[68,6213,6214,6216,6218,6220,6223,6226,6229,6231,6233],{"class":70,"line":151},[68,6215,4093],{"class":89},[68,6217,6052],{"class":85},[68,6219,90],{"class":89},[68,6221,6222],{"class":1157},"\"Name\"",[68,6224,6225],{"class":89},").",[68,6227,6228],{"class":85},"SetString",[68,6230,90],{"class":89},[68,6232,5737],{"class":1157},[68,6234,2781],{"class":89},[339,6236,6237],{},"Рефлексия = аллокации, type assertions, поиск по имени. На горячих путях — критично.",[50,6239,6241],{"id":6240},"сложность-кода","Сложность кода",[59,6243,6245],{"className":61,"code":6244,"language":63,"meta":5,"style":5},"\u002F\u002F Прямой код — понятно\nresult := vec.Add(Vec{3, 4})\n\n\u002F\u002F Рефлексия — «гуглить надо»\nv := reflect.ValueOf(vec)\nmethod := v.MethodByName(\"Add\")\nargs := []reflect.Value{reflect.ValueOf(Vec{3, 4})}\nresult := method.Call(args)\n",[65,6246,6247,6252,6278,6282,6287,6300,6317,6350],{"__ignoreMap":5},[68,6248,6249],{"class":70,"line":71},[68,6250,6251],{"class":74},"\u002F\u002F Прямой код — понятно\n",[68,6253,6254,6257,6259,6262,6264,6266,6268,6270,6272,6274,6276],{"class":70,"line":78},[68,6255,6256],{"class":89},"result ",[68,6258,2754],{"class":81},[68,6260,6261],{"class":89}," vec.",[68,6263,2656],{"class":85},[68,6265,90],{"class":89},[68,6267,4952],{"class":85},[68,6269,5015],{"class":89},[68,6271,3165],{"class":302},[68,6273,97],{"class":89},[68,6275,5077],{"class":302},[68,6277,5024],{"class":89},[68,6279,6280],{"class":70,"line":115},[68,6281,155],{"emptyLinePlaceholder":154},[68,6283,6284],{"class":70,"line":136},[68,6285,6286],{"class":74},"\u002F\u002F Рефлексия — «гуглить надо»\n",[68,6288,6289,6291,6293,6295,6297],{"class":70,"line":145},[68,6290,3854],{"class":89},[68,6292,2754],{"class":81},[68,6294,3841],{"class":89},[68,6296,3751],{"class":85},[68,6298,6299],{"class":89},"(vec)\n",[68,6301,6302,6305,6307,6309,6311,6313,6315],{"class":70,"line":151},[68,6303,6304],{"class":89},"method ",[68,6306,2754],{"class":81},[68,6308,3992],{"class":89},[68,6310,5036],{"class":85},[68,6312,90],{"class":89},[68,6314,5041],{"class":1157},[68,6316,2781],{"class":89},[68,6318,6319,6322,6324,6326,6328,6330,6332,6334,6336,6338,6340,6342,6344,6346,6348],{"class":70,"line":158},[68,6320,6321],{"class":89},"args ",[68,6323,2754],{"class":81},[68,6325,2127],{"class":89},[68,6327,3795],{"class":85},[68,6329,587],{"class":89},[68,6331,5059],{"class":85},[68,6333,5062],{"class":89},[68,6335,3751],{"class":85},[68,6337,90],{"class":89},[68,6339,4952],{"class":85},[68,6341,5015],{"class":89},[68,6343,3165],{"class":302},[68,6345,97],{"class":89},[68,6347,5077],{"class":302},[68,6349,5080],{"class":89},[68,6351,6352,6354,6356,6358,6360],{"class":70,"line":184},[68,6353,6256],{"class":89},[68,6355,2754],{"class":81},[68,6357,5090],{"class":89},[68,6359,5093],{"class":85},[68,6361,5096],{"class":89},[339,6363,6364],{},"У reflect.Value — десятки методов. Запомнить нереально, всегда гуглить.",[50,6366,6368],{"id":6367},"паники-в-рантайме","Паники в рантайме",[59,6370,6372],{"className":61,"code":6371,"language":63,"meta":5,"style":5},"\u002F\u002F Попытка изменить копию\nv := reflect.ValueOf(3.14)\nv.SetFloat(2.0)  \u002F\u002F ПАНИКА: using unaddressable value\n\n\u002F\u002F Лишний Elem()\nv := reflect.ValueOf(42)\nv.Elem()  \u002F\u002F ПАНИКА: call of reflect.Value.Elem on int Value\n\n\u002F\u002F Index на nil-slice\ns := reflect.ValueOf([]int(nil))\ns.Index(0)  \u002F\u002F ПАНИКА\n",[65,6373,6374,6379,6395,6409,6413,6418,6434,6445,6449,6454,6474],{"__ignoreMap":5},[68,6375,6376],{"class":70,"line":71},[68,6377,6378],{"class":74},"\u002F\u002F Попытка изменить копию\n",[68,6380,6381,6383,6385,6387,6389,6391,6393],{"class":70,"line":78},[68,6382,3854],{"class":89},[68,6384,2754],{"class":81},[68,6386,3841],{"class":89},[68,6388,3751],{"class":85},[68,6390,90],{"class":89},[68,6392,1441],{"class":302},[68,6394,2781],{"class":89},[68,6396,6397,6399,6401,6403,6405,6407],{"class":70,"line":115},[68,6398,4093],{"class":89},[68,6400,4096],{"class":85},[68,6402,90],{"class":89},[68,6404,3204],{"class":302},[68,6406,1444],{"class":89},[68,6408,4106],{"class":74},[68,6410,6411],{"class":70,"line":136},[68,6412,155],{"emptyLinePlaceholder":154},[68,6414,6415],{"class":70,"line":145},[68,6416,6417],{"class":74},"\u002F\u002F Лишний Elem()\n",[68,6419,6420,6422,6424,6426,6428,6430,6432],{"class":70,"line":151},[68,6421,3854],{"class":89},[68,6423,2754],{"class":81},[68,6425,3841],{"class":89},[68,6427,3751],{"class":85},[68,6429,90],{"class":89},[68,6431,1334],{"class":302},[68,6433,2781],{"class":89},[68,6435,6436,6438,6440,6442],{"class":70,"line":158},[68,6437,4093],{"class":89},[68,6439,4180],{"class":85},[68,6441,1278],{"class":89},[68,6443,6444],{"class":74},"\u002F\u002F ПАНИКА: call of reflect.Value.Elem on int Value\n",[68,6446,6447],{"class":70,"line":184},[68,6448,155],{"emptyLinePlaceholder":154},[68,6450,6451],{"class":70,"line":199},[68,6452,6453],{"class":74},"\u002F\u002F Index на nil-slice\n",[68,6455,6456,6458,6460,6462,6464,6466,6468,6470,6472],{"class":70,"line":206},[68,6457,1626],{"class":89},[68,6459,2754],{"class":81},[68,6461,3841],{"class":89},[68,6463,3751],{"class":85},[68,6465,5150],{"class":89},[68,6467,109],{"class":81},[68,6469,90],{"class":89},[68,6471,5302],{"class":302},[68,6473,4833],{"class":89},[68,6475,6476,6478,6480,6482,6484,6486],{"class":70,"line":2425},[68,6477,2772],{"class":89},[68,6479,5570],{"class":85},[68,6481,90],{"class":89},[68,6483,2151],{"class":302},[68,6485,1444],{"class":89},[68,6487,6488],{"class":74},"\u002F\u002F ПАНИКА\n",[339,6490,6491],{},"Рефлексия переносит ошибки из compile-time в runtime.",[50,6493,6495],{"id":6494},"gc-ловушка-pointer-возвращает-uintptr","GC-ловушка: Pointer() возвращает uintptr",[59,6497,6499],{"className":61,"code":6498,"language":63,"meta":5,"style":5},"v := reflect.ValueOf(&obj)\nptr := v.Pointer()  \u002F\u002F uintptr — просто число!\n\n\u002F\u002F Между этими строками GC может собрать obj,\n\u002F\u002F потому что uintptr НЕ удерживает объект\nruntime.GC()\n\n\u002F\u002F ptr теперь указывает на освобождённую память!\nuse(unsafe.Pointer(ptr))  \u002F\u002F 💥 use-after-free\n",[65,6500,6501,6518,6534,6538,6543,6548,6558,6562,6567],{"__ignoreMap":5},[68,6502,6503,6505,6507,6509,6511,6513,6515],{"class":70,"line":71},[68,6504,3854],{"class":89},[68,6506,2754],{"class":81},[68,6508,3841],{"class":89},[68,6510,3751],{"class":85},[68,6512,90],{"class":89},[68,6514,4131],{"class":81},[68,6516,6517],{"class":89},"obj)\n",[68,6519,6520,6523,6525,6527,6529,6531],{"class":70,"line":78},[68,6521,6522],{"class":89},"ptr ",[68,6524,2754],{"class":81},[68,6526,3992],{"class":89},[68,6528,6068],{"class":85},[68,6530,1278],{"class":89},[68,6532,6533],{"class":74},"\u002F\u002F uintptr — просто число!\n",[68,6535,6536],{"class":70,"line":115},[68,6537,155],{"emptyLinePlaceholder":154},[68,6539,6540],{"class":70,"line":136},[68,6541,6542],{"class":74},"\u002F\u002F Между этими строками GC может собрать obj,\n",[68,6544,6545],{"class":70,"line":145},[68,6546,6547],{"class":74},"\u002F\u002F потому что uintptr НЕ удерживает объект\n",[68,6549,6550,6553,6556],{"class":70,"line":151},[68,6551,6552],{"class":89},"runtime.",[68,6554,6555],{"class":85},"GC",[68,6557,4183],{"class":89},[68,6559,6560],{"class":70,"line":158},[68,6561,155],{"emptyLinePlaceholder":154},[68,6563,6564],{"class":70,"line":184},[68,6565,6566],{"class":74},"\u002F\u002F ptr теперь указывает на освобождённую память!\n",[68,6568,6569,6572,6575,6577,6580],{"class":70,"line":199},[68,6570,6571],{"class":85},"use",[68,6573,6574],{"class":89},"(unsafe.",[68,6576,6068],{"class":85},[68,6578,6579],{"class":89},"(ptr))  ",[68,6581,6582],{"class":74},"\u002F\u002F 💥 use-after-free\n",[339,6584,6585,3872,6587,6590],{},[65,6586,6148],{},[65,6588,6589],{},"uintptr"," — это просто целое число, GC не считает его ссылкой на объект.",[50,6592,6594],{"id":6593},"решение-unsafepointer","Решение: UnsafePointer()",[59,6596,6598],{"className":61,"code":6597,"language":63,"meta":5,"style":5},"v := reflect.ValueOf(&obj)\nptr := v.UnsafePointer()  \u002F\u002F unsafe.Pointer — удерживает объект\n\n\u002F\u002F GC НЕ соберёт obj, пока ptr жив\nruntime.GC()\nuse(ptr)  \u002F\u002F ✅ безопасно\n",[65,6599,6600,6616,6632,6636,6641,6649],{"__ignoreMap":5},[68,6601,6602,6604,6606,6608,6610,6612,6614],{"class":70,"line":71},[68,6603,3854],{"class":89},[68,6605,2754],{"class":81},[68,6607,3841],{"class":89},[68,6609,3751],{"class":85},[68,6611,90],{"class":89},[68,6613,4131],{"class":81},[68,6615,6517],{"class":89},[68,6617,6618,6620,6622,6624,6627,6629],{"class":70,"line":78},[68,6619,6522],{"class":89},[68,6621,2754],{"class":81},[68,6623,3992],{"class":89},[68,6625,6626],{"class":85},"UnsafePointer",[68,6628,1278],{"class":89},[68,6630,6631],{"class":74},"\u002F\u002F unsafe.Pointer — удерживает объект\n",[68,6633,6634],{"class":70,"line":115},[68,6635,155],{"emptyLinePlaceholder":154},[68,6637,6638],{"class":70,"line":136},[68,6639,6640],{"class":74},"\u002F\u002F GC НЕ соберёт obj, пока ptr жив\n",[68,6642,6643,6645,6647],{"class":70,"line":145},[68,6644,6552],{"class":89},[68,6646,6555],{"class":85},[68,6648,4183],{"class":89},[68,6650,6651,6653,6656],{"class":70,"line":151},[68,6652,6571],{"class":85},[68,6654,6655],{"class":89},"(ptr)  ",[68,6657,6658],{"class":74},"\u002F\u002F ✅ безопасно\n",[339,6660,6661,3872,6664,6666],{},[65,6662,6663],{},"UnsafePointer()",[65,6665,6113],{}," — GC видит эту ссылку и не собирает объект.",[50,6668,6670],{"id":6669},"ограничения-рефлексии","Ограничения рефлексии",[339,6672,6673],{},"Планировалось: всё что можно написать без рефлексии — можно и с ней. Почти получилось, но есть исключения:",[339,6675,6676],{},"Нельзя создать интерфейсный тип через reflect (до Go 1.22).",[339,6678,6679],{},"Нельзя создать новый type definition через reflect.",[339,6681,6682],{},"Проблемы с анонимными полями в структурах.",[42,6684],{},[11,6686,6687,6694,6704,6712,6719],{},[14,6688,6689,6690,6693],{},"теги = ",[18,6691,6692],{},"ключ-значение"," пары в бэктиках после поля структуры",[14,6695,6696,6697,6700,6701],{},"доступ через рефлексию: ",[65,6698,6699],{},"Field(i).Tag.Get(\"json\")"," или ",[65,6702,6703],{},"Lookup(\"json\")",[14,6705,6706,3872,6709,6711],{},[65,6707,6708],{},"Lookup",[65,6710,2166],{}," — можно отличить пустой тег от отсутствующего",[14,6713,6714,6715,6718],{},"парсинг значения (omitempty, name) — ",[18,6716,6717],{},"вручную",", рефлексия отдаёт только строку",[14,6720,6721],{},"основа для JSON\u002FXML сериализации, валидаторов, ORM",[42,6723],{},[50,6725,6727],{"id":6726},"struct-tags","Struct tags",[50,6729,6731],{"id":6730},"синтаксис-тегов","Синтаксис тегов",[59,6733,6735],{"className":61,"code":6734,"language":63,"meta":5,"style":5},"type User struct {\n    Name  string `json:\"name\" xml:\"user_name\"`\n    Email string `json:\"email,omitempty\"`\n    Age   int    `json:\"-\"`  \u002F\u002F игнорировать при сериализации\n}\n",[65,6736,6737,6747,6757,6766,6778],{"__ignoreMap":5},[68,6738,6739,6741,6743,6745],{"class":70,"line":71},[68,6740,493],{"class":81},[68,6742,4475],{"class":85},[68,6744,1604],{"class":81},[68,6746,112],{"class":89},[68,6748,6749,6752,6754],{"class":70,"line":78},[68,6750,6751],{"class":89},"    Name  ",[68,6753,576],{"class":81},[68,6755,6756],{"class":1157}," `json:\"name\" xml:\"user_name\"`\n",[68,6758,6759,6761,6763],{"class":70,"line":115},[68,6760,5780],{"class":89},[68,6762,576],{"class":81},[68,6764,6765],{"class":1157}," `json:\"email,omitempty\"`\n",[68,6767,6768,6770,6772,6775],{"class":70,"line":136},[68,6769,5790],{"class":89},[68,6771,109],{"class":81},[68,6773,6774],{"class":1157},"    `json:\"-\"`",[68,6776,6777],{"class":74},"  \u002F\u002F игнорировать при сериализации\n",[68,6779,6780],{"class":70,"line":145},[68,6781,148],{"class":89},[339,6783,6784,6785,6788,6789,6792],{},"Формат: ",[65,6786,6787],{},"ключ:\"значение\""," через пробел. Значение — произвольная строка, парсинг на вашей стороне. Тег ",[65,6790,6791],{},"json:\"-\""," означает «игнорировать поле при сериализации».",[339,6794,6795,6796,3878,6799,6801,6802,6805],{},"Одному полю можно назначить несколько тегов для разных пакетов: ",[65,6797,6798],{},"json:\"name\" xml:\"user_name\"",[65,6800,5755],{}," прочитает свой тег, ",[65,6803,6804],{},"encoding\u002Fxml"," — свой.",[50,6807,6809],{"id":6808},"чтение-тегов-через-рефлексию","Чтение тегов через рефлексию",[59,6811,6813],{"className":61,"code":6812,"language":63,"meta":5,"style":5},"type User struct {\n    Name  string `json:\"name\" xml:\"user_name\"`\n    Email string `json:\"email,omitempty\"`\n    Age   int    `json:\"-\"`\n}\n\nt := reflect.TypeOf(User{})\n\n\u002F\u002F Поле Name\nfield0 := t.Field(0)\nfmt.Println(field0.Tag)                    \u002F\u002F json:\"name\" xml:\"user_name\"\nfmt.Println(field0.Tag.Get(\"json\"))        \u002F\u002F \"name\"\nfmt.Println(field0.Tag.Get(\"xml\"))         \u002F\u002F \"user_name\"\n\n\u002F\u002F Поле Email\nfield1 := t.Field(1)\nfmt.Println(field1.Tag.Get(\"json\"))        \u002F\u002F \"email,omitempty\"\n",[65,6814,6815,6825,6833,6841,6850,6854,6858,6874,6878,6883,6901,6913,6936,6957,6961,6966,6983],{"__ignoreMap":5},[68,6816,6817,6819,6821,6823],{"class":70,"line":71},[68,6818,493],{"class":81},[68,6820,4475],{"class":85},[68,6822,1604],{"class":81},[68,6824,112],{"class":89},[68,6826,6827,6829,6831],{"class":70,"line":78},[68,6828,6751],{"class":89},[68,6830,576],{"class":81},[68,6832,6756],{"class":1157},[68,6834,6835,6837,6839],{"class":70,"line":115},[68,6836,5780],{"class":89},[68,6838,576],{"class":81},[68,6840,6765],{"class":1157},[68,6842,6843,6845,6847],{"class":70,"line":136},[68,6844,5790],{"class":89},[68,6846,109],{"class":81},[68,6848,6849],{"class":1157},"    `json:\"-\"`\n",[68,6851,6852],{"class":70,"line":145},[68,6853,148],{"class":89},[68,6855,6856],{"class":70,"line":151},[68,6857,155],{"emptyLinePlaceholder":154},[68,6859,6860,6862,6864,6866,6868,6870,6872],{"class":70,"line":158},[68,6861,3836],{"class":89},[68,6863,2754],{"class":81},[68,6865,3841],{"class":89},[68,6867,3748],{"class":85},[68,6869,90],{"class":89},[68,6871,4515],{"class":85},[68,6873,4558],{"class":89},[68,6875,6876],{"class":70,"line":184},[68,6877,155],{"emptyLinePlaceholder":154},[68,6879,6880],{"class":70,"line":199},[68,6881,6882],{"class":74},"\u002F\u002F Поле Name\n",[68,6884,6885,6888,6890,6893,6895,6897,6899],{"class":70,"line":206},[68,6886,6887],{"class":89},"field0 ",[68,6889,2754],{"class":81},[68,6891,6892],{"class":89}," t.",[68,6894,4596],{"class":85},[68,6896,90],{"class":89},[68,6898,2151],{"class":302},[68,6900,2781],{"class":89},[68,6902,6903,6905,6907,6910],{"class":70,"line":2425},[68,6904,4074],{"class":89},[68,6906,3136],{"class":85},[68,6908,6909],{"class":89},"(field0.Tag)                    ",[68,6911,6912],{"class":74},"\u002F\u002F json:\"name\" xml:\"user_name\"\n",[68,6914,6915,6917,6919,6922,6925,6927,6930,6933],{"class":70,"line":2437},[68,6916,4074],{"class":89},[68,6918,3136],{"class":85},[68,6920,6921],{"class":89},"(field0.Tag.",[68,6923,6924],{"class":85},"Get",[68,6926,90],{"class":89},[68,6928,6929],{"class":1157},"\"json\"",[68,6931,6932],{"class":89},"))        ",[68,6934,6935],{"class":74},"\u002F\u002F \"name\"\n",[68,6937,6938,6940,6942,6944,6946,6948,6951,6954],{"class":70,"line":2449},[68,6939,4074],{"class":89},[68,6941,3136],{"class":85},[68,6943,6921],{"class":89},[68,6945,6924],{"class":85},[68,6947,90],{"class":89},[68,6949,6950],{"class":1157},"\"xml\"",[68,6952,6953],{"class":89},"))         ",[68,6955,6956],{"class":74},"\u002F\u002F \"user_name\"\n",[68,6958,6959],{"class":70,"line":2687},[68,6960,155],{"emptyLinePlaceholder":154},[68,6962,6963],{"class":70,"line":2693},[68,6964,6965],{"class":74},"\u002F\u002F Поле Email\n",[68,6967,6968,6971,6973,6975,6977,6979,6981],{"class":70,"line":2722},[68,6969,6970],{"class":89},"field1 ",[68,6972,2754],{"class":81},[68,6974,6892],{"class":89},[68,6976,4596],{"class":85},[68,6978,90],{"class":89},[68,6980,303],{"class":302},[68,6982,2781],{"class":89},[68,6984,6985,6987,6989,6992,6994,6996,6998,7000],{"class":70,"line":2733},[68,6986,4074],{"class":89},[68,6988,3136],{"class":85},[68,6990,6991],{"class":89},"(field1.Tag.",[68,6993,6924],{"class":85},[68,6995,90],{"class":89},[68,6997,6929],{"class":1157},[68,6999,6932],{"class":89},[68,7001,7002],{"class":74},"\u002F\u002F \"email,omitempty\"\n",[339,7004,7005,7006,2791,7009,7011,7012,7015,7016,7019],{},"Доступ к тегам — через ",[65,7007,7008],{},"reflect.TypeOf",[65,7010,3751],{},": теги — это метаданные типа, а не значения. ",[65,7013,7014],{},"field.Tag"," возвращает полную строку тегов, ",[65,7017,7018],{},"Tag.Get(key)"," — значение для конкретного ключа.",[50,7021,7023],{"id":7022},"lookup-vs-get","Lookup vs Get",[59,7025,7027],{"className":61,"code":7026,"language":63,"meta":5,"style":5},"\u002F\u002F Get — вернёт \"\" и для пустого тега, и для отсутствующего\nval := field.Tag.Get(\"missing\")  \u002F\u002F \"\" — непонятно, есть тег или нет\n\n\u002F\u002F Lookup — различает\nval, ok := field.Tag.Lookup(\"json\")\nif ok {\n    \u002F\u002F тег есть, val может быть \"\"\n} else {\n    \u002F\u002F тега нет\n}\n",[65,7028,7029,7034,7056,7060,7065,7081,7089,7094,7104,7109],{"__ignoreMap":5},[68,7030,7031],{"class":70,"line":71},[68,7032,7033],{"class":74},"\u002F\u002F Get — вернёт \"\" и для пустого тега, и для отсутствующего\n",[68,7035,7036,7039,7041,7044,7046,7048,7051,7053],{"class":70,"line":78},[68,7037,7038],{"class":89},"val ",[68,7040,2754],{"class":81},[68,7042,7043],{"class":89}," field.Tag.",[68,7045,6924],{"class":85},[68,7047,90],{"class":89},[68,7049,7050],{"class":1157},"\"missing\"",[68,7052,1444],{"class":89},[68,7054,7055],{"class":74},"\u002F\u002F \"\" — непонятно, есть тег или нет\n",[68,7057,7058],{"class":70,"line":115},[68,7059,155],{"emptyLinePlaceholder":154},[68,7061,7062],{"class":70,"line":136},[68,7063,7064],{"class":74},"\u002F\u002F Lookup — различает\n",[68,7066,7067,7069,7071,7073,7075,7077,7079],{"class":70,"line":145},[68,7068,5395],{"class":89},[68,7070,2754],{"class":81},[68,7072,7043],{"class":89},[68,7074,6708],{"class":85},[68,7076,90],{"class":89},[68,7078,6929],{"class":1157},[68,7080,2781],{"class":89},[68,7082,7083,7086],{"class":70,"line":151},[68,7084,7085],{"class":81},"if",[68,7087,7088],{"class":89}," ok {\n",[68,7090,7091],{"class":70,"line":158},[68,7092,7093],{"class":74},"    \u002F\u002F тег есть, val может быть \"\"\n",[68,7095,7096,7099,7102],{"class":70,"line":184},[68,7097,7098],{"class":89},"} ",[68,7100,7101],{"class":81},"else",[68,7103,112],{"class":89},[68,7105,7106],{"class":70,"line":199},[68,7107,7108],{"class":74},"    \u002F\u002F тега нет\n",[68,7110,7111],{"class":70,"line":206},[68,7112,148],{"class":89},[339,7114,7115,7117,7118,2923,7120,3872,7122,3878,7124,7127],{},[65,7116,6924],{}," не позволяет отличить отсутствующий тег от тега с пустым значением — оба вернут ",[65,7119,4774],{},[65,7121,6708],{},[65,7123,2166],{},[65,7125,7126],{},"ok=false"," означает, что тега нет совсем.",[50,7129,7131],{"id":7130},"парсинг-значения-вручную","Парсинг значения — вручную",[59,7133,7135],{"className":61,"code":7134,"language":63,"meta":5,"style":5},"tag := field.Tag.Get(\"json\")  \u002F\u002F \"email,omitempty\"\n\n\u002F\u002F Рефлексия отдаёт строку целиком, дальше — сами\nparts := strings.Split(tag, \",\")\nname := parts[0]                \u002F\u002F \"email\"\nomitempty := len(parts) > 1 && parts[1] == \"omitempty\"  \u002F\u002F true\n",[65,7136,7137,7156,7160,7165,7186,7204],{"__ignoreMap":5},[68,7138,7139,7142,7144,7146,7148,7150,7152,7154],{"class":70,"line":71},[68,7140,7141],{"class":89},"tag ",[68,7143,2754],{"class":81},[68,7145,7043],{"class":89},[68,7147,6924],{"class":85},[68,7149,90],{"class":89},[68,7151,6929],{"class":1157},[68,7153,1444],{"class":89},[68,7155,7002],{"class":74},[68,7157,7158],{"class":70,"line":78},[68,7159,155],{"emptyLinePlaceholder":154},[68,7161,7162],{"class":70,"line":115},[68,7163,7164],{"class":74},"\u002F\u002F Рефлексия отдаёт строку целиком, дальше — сами\n",[68,7166,7167,7170,7172,7175,7178,7181,7184],{"class":70,"line":136},[68,7168,7169],{"class":89},"parts ",[68,7171,2754],{"class":81},[68,7173,7174],{"class":89}," strings.",[68,7176,7177],{"class":85},"Split",[68,7179,7180],{"class":89},"(tag, ",[68,7182,7183],{"class":1157},"\",\"",[68,7185,2781],{"class":89},[68,7187,7188,7191,7193,7196,7198,7201],{"class":70,"line":145},[68,7189,7190],{"class":89},"name ",[68,7192,2754],{"class":81},[68,7194,7195],{"class":89}," parts[",[68,7197,2151],{"class":302},[68,7199,7200],{"class":89},"]                ",[68,7202,7203],{"class":74},"\u002F\u002F \"email\"\n",[68,7205,7206,7209,7211,7213,7216,7218,7221,7224,7226,7228,7230,7232,7235],{"class":70,"line":151},[68,7207,7208],{"class":89},"omitempty ",[68,7210,2754],{"class":81},[68,7212,2727],{"class":85},[68,7214,7215],{"class":89},"(parts) ",[68,7217,124],{"class":81},[68,7219,7220],{"class":302}," 1",[68,7222,7223],{"class":81}," &&",[68,7225,7195],{"class":89},[68,7227,303],{"class":302},[68,7229,1309],{"class":89},[68,7231,1017],{"class":81},[68,7233,7234],{"class":1157}," \"omitempty\"",[68,7236,7237],{"class":74},"  \u002F\u002F true\n",[339,7239,7240,7241,7243],{},"Рефлексия возвращает значение тега как единую строку — разбор опций (omitempty, name и т.д.) целиком лежит на вызывающем коде. ",[65,7242,5755],{}," делает это внутри себя.",[50,7245,7247],{"id":7246},"как-это-использует-encodingjson","Как это использует encoding\u002Fjson",[59,7249,7251],{"className":61,"code":7250,"language":63,"meta":5,"style":5},"\u002F\u002F Упрощённо: что делает json.Marshal внутри\nt := reflect.TypeOf(obj)\nv := reflect.ValueOf(obj)\n\nfor i := 0; i \u003C t.NumField(); i++ {\n    field := t.Field(i)\n    tag := field.Tag.Get(\"json\")\n    value := v.Field(i)\n    \u002F\u002F парсим tag, сериализуем value...\n}\n",[65,7252,7253,7258,7271,7283,7287,7317,7331,7348,7361,7366],{"__ignoreMap":5},[68,7254,7255],{"class":70,"line":71},[68,7256,7257],{"class":74},"\u002F\u002F Упрощённо: что делает json.Marshal внутри\n",[68,7259,7260,7262,7264,7266,7268],{"class":70,"line":78},[68,7261,3836],{"class":89},[68,7263,2754],{"class":81},[68,7265,3841],{"class":89},[68,7267,3748],{"class":85},[68,7269,7270],{"class":89},"(obj)\n",[68,7272,7273,7275,7277,7279,7281],{"class":70,"line":115},[68,7274,3854],{"class":89},[68,7276,2754],{"class":81},[68,7278,3841],{"class":89},[68,7280,3751],{"class":85},[68,7282,7270],{"class":89},[68,7284,7285],{"class":70,"line":136},[68,7286,155],{"emptyLinePlaceholder":154},[68,7288,7289,7292,7295,7297,7299,7302,7305,7307,7309,7312,7315],{"class":70,"line":145},[68,7290,7291],{"class":81},"for",[68,7293,7294],{"class":89}," i ",[68,7296,2754],{"class":81},[68,7298,1755],{"class":302},[68,7300,7301],{"class":89},"; i ",[68,7303,7304],{"class":81},"\u003C",[68,7306,6892],{"class":89},[68,7308,4583],{"class":85},[68,7310,7311],{"class":89},"(); i",[68,7313,7314],{"class":81},"++",[68,7316,112],{"class":89},[68,7318,7319,7322,7324,7326,7328],{"class":70,"line":151},[68,7320,7321],{"class":89},"    field ",[68,7323,2754],{"class":81},[68,7325,6892],{"class":89},[68,7327,4596],{"class":85},[68,7329,7330],{"class":89},"(i)\n",[68,7332,7333,7336,7338,7340,7342,7344,7346],{"class":70,"line":158},[68,7334,7335],{"class":89},"    tag ",[68,7337,2754],{"class":81},[68,7339,7043],{"class":89},[68,7341,6924],{"class":85},[68,7343,90],{"class":89},[68,7345,6929],{"class":1157},[68,7347,2781],{"class":89},[68,7349,7350,7353,7355,7357,7359],{"class":70,"line":184},[68,7351,7352],{"class":89},"    value ",[68,7354,2754],{"class":81},[68,7356,3992],{"class":89},[68,7358,4596],{"class":85},[68,7360,7330],{"class":89},[68,7362,7363],{"class":70,"line":199},[68,7364,7365],{"class":74},"    \u002F\u002F парсим tag, сериализуем value...\n",[68,7367,7368],{"class":70,"line":206},[68,7369,148],{"class":89},[339,7371,7372,7375,7376,7378,7379,7381],{},[65,7373,7374],{},"json.Marshal"," перебирает поля через ",[65,7377,3748],{}," (для тегов) и ",[65,7380,3751],{}," (для значений) в одном цикле по индексу.",[42,7383],{},[11,7385,7386,7392,7402,7409,7418],{},[14,7387,7388,7391],{},[18,7389,7390],{},"интроспекция"," — исследовать тип\u002Fсвойства объекта в рантайме (только чтение)",[14,7393,7394,7397,7398,7401],{},[18,7395,7396],{},"рефлексия"," — исследовать ",[18,7399,7400],{},"и модифицировать"," структуру и поведение в рантайме",[14,7403,7404,7405,7408],{},"рефлексия = ",[18,7406,7407],{},"метапрограммирование в рантайме"," (дженерики = в compile-time)",[14,7410,7411,7412,7414,7415,7417],{},"два базовых типа: ",[65,7413,3875],{}," (TypeOf) и ",[65,7416,3881],{}," (ValueOf)",[14,7419,7420,7422,7423,7426],{},[18,7421,4570],{}," vs ",[18,7424,7425],{},"Type",": kind = базовый тип (int), type = конкретный (MyInt). Для alias: kind == type",[42,7428],{},[50,7430,7432],{"id":7431},"интроспекция-type-и-value","Интроспекция, Type и Value",[50,7434,7436],{"id":7435},"интроспекция-vs-рефлексия","Интроспекция vs рефлексия",[59,7438,7441],{"className":7439,"code":7440,"language":4273},[4271],"Интроспекция: «что это за объект? какие у него поля? методы?»\nРефлексия:    «что это за объект? + давай поменяем ему поля и вызовем методы»\n",[65,7442,7440],{"__ignoreMap":5},[339,7444,7445,7446,587],{},"Go поддерживает полную рефлексию через пакет ",[65,7447,3795],{},[50,7449,7451],{"id":7450},"reflecttype-и-reflectvalue","reflect.Type и reflect.Value",[59,7453,7455],{"className":61,"code":7454,"language":63,"meta":5,"style":5},"var x float64 = 3.14\n\nt := reflect.TypeOf(x)   \u002F\u002F reflect.Type — информация о типе\nv := reflect.ValueOf(x)  \u002F\u002F reflect.Value — информация о значении\n\nfmt.Println(t)            \u002F\u002F float64\nfmt.Println(v)            \u002F\u002F 3.14\nfmt.Println(v.Type())     \u002F\u002F float64\n",[65,7456,7457,7469,7473,7488,7503,7507,7519,7530],{"__ignoreMap":5},[68,7458,7459,7461,7463,7465,7467],{"class":70,"line":71},[68,7460,1264],{"class":81},[68,7462,1748],{"class":89},[68,7464,3687],{"class":81},[68,7466,1273],{"class":81},[68,7468,3822],{"class":302},[68,7470,7471],{"class":70,"line":78},[68,7472,155],{"emptyLinePlaceholder":154},[68,7474,7475,7477,7479,7481,7483,7485],{"class":70,"line":115},[68,7476,3836],{"class":89},[68,7478,2754],{"class":81},[68,7480,3841],{"class":89},[68,7482,3748],{"class":85},[68,7484,3846],{"class":89},[68,7486,7487],{"class":74},"\u002F\u002F reflect.Type — информация о типе\n",[68,7489,7490,7492,7494,7496,7498,7500],{"class":70,"line":136},[68,7491,3854],{"class":89},[68,7493,2754],{"class":81},[68,7495,3841],{"class":89},[68,7497,3751],{"class":85},[68,7499,3863],{"class":89},[68,7501,7502],{"class":74},"\u002F\u002F reflect.Value — информация о значении\n",[68,7504,7505],{"class":70,"line":145},[68,7506,155],{"emptyLinePlaceholder":154},[68,7508,7509,7511,7513,7516],{"class":70,"line":151},[68,7510,4074],{"class":89},[68,7512,3136],{"class":85},[68,7514,7515],{"class":89},"(t)            ",[68,7517,7518],{"class":74},"\u002F\u002F float64\n",[68,7520,7521,7523,7525,7528],{"class":70,"line":158},[68,7522,4074],{"class":89},[68,7524,3136],{"class":85},[68,7526,7527],{"class":89},"(v)            ",[68,7529,4015],{"class":74},[68,7531,7532,7534,7536,7538,7540,7542],{"class":70,"line":184},[68,7533,4074],{"class":89},[68,7535,3136],{"class":85},[68,7537,4079],{"class":89},[68,7539,7425],{"class":85},[68,7541,5525],{"class":89},[68,7543,7518],{"class":74},[339,7545,7546,7547,7549],{},"Под капотом: TypeOf и ValueOf принимают ",[65,7548,378],{}," → неявное преобразование в пустой интерфейс → анализ двух указателей интерфейса (itab + data).",[50,7551,7553],{"id":7552},"kind-vs-type","Kind vs Type",[59,7555,7557],{"className":61,"code":7556,"language":63,"meta":5,"style":5},"type MyInt int\n\nvar a int = 42\nvar b MyInt = 42\n\n\u002F\u002F alias (type MyAlias = int)\nta := reflect.TypeOf(a)\nfmt.Println(ta.Name(), ta.Kind())  \u002F\u002F int, int  — совпадают\n\n\u002F\u002F type definition (type MyInt int)\ntb := reflect.TypeOf(b)\nfmt.Println(tb.Name(), tb.Kind())  \u002F\u002F MyInt, int — различаются!\n",[65,7558,7559,7568,7572,7584,7597,7601,7606,7620,7642,7646,7651,7665],{"__ignoreMap":5},[68,7560,7561,7563,7565],{"class":70,"line":71},[68,7562,493],{"class":81},[68,7564,681],{"class":85},[68,7566,7567],{"class":81}," int\n",[68,7569,7570],{"class":70,"line":78},[68,7571,155],{"emptyLinePlaceholder":154},[68,7573,7574,7576,7578,7580,7582],{"class":70,"line":115},[68,7575,1264],{"class":81},[68,7577,121],{"class":89},[68,7579,109],{"class":81},[68,7581,1273],{"class":81},[68,7583,4298],{"class":302},[68,7585,7586,7588,7591,7593,7595],{"class":70,"line":136},[68,7587,1264],{"class":81},[68,7589,7590],{"class":89}," b ",[68,7592,748],{"class":85},[68,7594,1273],{"class":81},[68,7596,4298],{"class":302},[68,7598,7599],{"class":70,"line":145},[68,7600,155],{"emptyLinePlaceholder":154},[68,7602,7603],{"class":70,"line":151},[68,7604,7605],{"class":74},"\u002F\u002F alias (type MyAlias = int)\n",[68,7607,7608,7611,7613,7615,7617],{"class":70,"line":158},[68,7609,7610],{"class":89},"ta ",[68,7612,2754],{"class":81},[68,7614,3841],{"class":89},[68,7616,3748],{"class":85},[68,7618,7619],{"class":89},"(a)\n",[68,7621,7622,7624,7626,7629,7632,7635,7637,7639],{"class":70,"line":184},[68,7623,4074],{"class":89},[68,7625,3136],{"class":85},[68,7627,7628],{"class":89},"(ta.",[68,7630,7631],{"class":85},"Name",[68,7633,7634],{"class":89},"(), ta.",[68,7636,4570],{"class":85},[68,7638,5510],{"class":89},[68,7640,7641],{"class":74},"\u002F\u002F int, int  — совпадают\n",[68,7643,7644],{"class":70,"line":199},[68,7645,155],{"emptyLinePlaceholder":154},[68,7647,7648],{"class":70,"line":206},[68,7649,7650],{"class":74},"\u002F\u002F type definition (type MyInt int)\n",[68,7652,7653,7656,7658,7660,7662],{"class":70,"line":2425},[68,7654,7655],{"class":89},"tb ",[68,7657,2754],{"class":81},[68,7659,3841],{"class":89},[68,7661,3748],{"class":85},[68,7663,7664],{"class":89},"(b)\n",[68,7666,7667,7669,7671,7674,7676,7679,7681,7683],{"class":70,"line":2437},[68,7668,4074],{"class":89},[68,7670,3136],{"class":85},[68,7672,7673],{"class":89},"(tb.",[68,7675,7631],{"class":85},[68,7677,7678],{"class":89},"(), tb.",[68,7680,4570],{"class":85},[68,7682,5510],{"class":89},[68,7684,7685],{"class":74},"\u002F\u002F MyInt, int — различаются!\n",[339,7687,7688,7689,7692,7693,7696],{},"Kind возвращает ",[18,7690,7691],{},"базовый"," тип (enum: int, string, struct, ptr, slice...). Type возвращает ",[18,7694,7695],{},"конкретный"," тип. Для type definition: Kind = базовый, Type = определённый.",[50,7698,7700],{"id":7699},"kind-для-проверок-в-коде","Kind для проверок в коде",[59,7702,7704],{"className":61,"code":7703,"language":63,"meta":5,"style":5},"x := 42\nv := reflect.ValueOf(x)\n\nswitch v.Kind() {\ncase reflect.Int:\n    fmt.Println(\"integer:\", v.Int())\ncase reflect.Float64:\n    fmt.Println(\"float:\", v.Float())\ncase reflect.String:\n    fmt.Println(\"string:\", v.String())\n}\n",[65,7705,7706,7715,7727,7731,7742,7750,7769,7776,7794,7801,7818],{"__ignoreMap":5},[68,7707,7708,7711,7713],{"class":70,"line":71},[68,7709,7710],{"class":89},"x ",[68,7712,2754],{"class":81},[68,7714,4298],{"class":302},[68,7716,7717,7719,7721,7723,7725],{"class":70,"line":78},[68,7718,3854],{"class":89},[68,7720,2754],{"class":81},[68,7722,3841],{"class":89},[68,7724,3751],{"class":85},[68,7726,3973],{"class":89},[68,7728,7729],{"class":70,"line":115},[68,7730,155],{"emptyLinePlaceholder":154},[68,7732,7733,7736,7738,7740],{"class":70,"line":136},[68,7734,7735],{"class":81},"switch",[68,7737,3992],{"class":89},[68,7739,4570],{"class":85},[68,7741,3947],{"class":89},[68,7743,7744,7747],{"class":70,"line":145},[68,7745,7746],{"class":81},"case",[68,7748,7749],{"class":89}," reflect.Int:\n",[68,7751,7752,7754,7756,7758,7761,7764,7767],{"class":70,"line":151},[68,7753,4007],{"class":89},[68,7755,3136],{"class":85},[68,7757,90],{"class":89},[68,7759,7760],{"class":1157},"\"integer:\"",[68,7762,7763],{"class":89},", v.",[68,7765,7766],{"class":85},"Int",[68,7768,6077],{"class":89},[68,7770,7771,7773],{"class":70,"line":158},[68,7772,7746],{"class":81},[68,7774,7775],{"class":89}," reflect.Float64:\n",[68,7777,7778,7780,7782,7784,7787,7789,7792],{"class":70,"line":184},[68,7779,4007],{"class":89},[68,7781,3136],{"class":85},[68,7783,90],{"class":89},[68,7785,7786],{"class":1157},"\"float:\"",[68,7788,7763],{"class":89},[68,7790,7791],{"class":85},"Float",[68,7793,6077],{"class":89},[68,7795,7796,7798],{"class":70,"line":199},[68,7797,7746],{"class":81},[68,7799,7800],{"class":89}," reflect.String:\n",[68,7802,7803,7805,7807,7809,7812,7814,7816],{"class":70,"line":206},[68,7804,4007],{"class":89},[68,7806,3136],{"class":85},[68,7808,90],{"class":89},[68,7810,7811],{"class":1157},"\"string:\"",[68,7813,7763],{"class":89},[68,7815,4622],{"class":85},[68,7817,6077],{"class":89},[68,7819,7820],{"class":70,"line":2425},[68,7821,148],{"class":89},[50,7823,7825],{"id":7824},"api-самый-большой-тип","API: самый большой тип",[59,7827,7829],{"className":61,"code":7828,"language":63,"meta":5,"style":5},"var x uint8 = 42\nv := reflect.ValueOf(x)\n\n\u002F\u002F Возвращает uint64 (самый большой), не uint8\nval := v.Uint()  \u002F\u002F uint64\n",[65,7830,7831,7844,7856,7860,7865],{"__ignoreMap":5},[68,7832,7833,7835,7837,7840,7842],{"class":70,"line":71},[68,7834,1264],{"class":81},[68,7836,1748],{"class":89},[68,7838,7839],{"class":81},"uint8",[68,7841,1273],{"class":81},[68,7843,4298],{"class":302},[68,7845,7846,7848,7850,7852,7854],{"class":70,"line":78},[68,7847,3854],{"class":89},[68,7849,2754],{"class":81},[68,7851,3841],{"class":89},[68,7853,3751],{"class":85},[68,7855,3973],{"class":89},[68,7857,7858],{"class":70,"line":115},[68,7859,155],{"emptyLinePlaceholder":154},[68,7861,7862],{"class":70,"line":136},[68,7863,7864],{"class":74},"\u002F\u002F Возвращает uint64 (самый большой), не uint8\n",[68,7866,7867,7869,7871,7873,7876,7878],{"class":70,"line":145},[68,7868,7038],{"class":89},[68,7870,2754],{"class":81},[68,7872,3992],{"class":89},[68,7874,7875],{"class":85},"Uint",[68,7877,1278],{"class":89},[68,7879,7880],{"class":74},"\u002F\u002F uint64\n",[339,7882,7883],{},"Для простоты API: getter-методы Value возвращают максимальный тип семейства (Int() → int64, Uint() → uint64, Float() → float64). Информация о реальном типе сохраняется в Kind\u002FType.",[42,7885],{},[45,7887,7889],{"id":7888},"практика","Практика",[7891,7892,7895,7898,7915],"quiz",{"answer":308,"id":7893,"xp":7894},"advanced-generics-reflect-q1","10",[339,7896,7897],{},"Когда дженерики обычно лучше рефлексии?",[7899,7900,7901],"template",{"v-slot:options":5},[11,7902,7903,7906,7909,7912],{},[14,7904,7905],{},"Когда нужно прочитать произвольные поля структуры по имени из JSON-тега",[14,7907,7908],{},"Когда алгоритм одинаковый для разных типов, а ошибки типов лучше ловить на этапе компиляции",[14,7910,7911],{},"Когда тип значения известен только после чтения конфигурации в runtime",[14,7913,7914],{},"Когда нужно обойти правила экспортируемости полей",[7899,7916,7917],{"v-slot:explanation":5},[339,7918,7919,7920,97,7923,97,7925,7928],{},"Дженерики подходят для повторяемой типобезопасной логики: ",[65,7921,7922],{},"Map",[65,7924,2581],{},[65,7926,7927],{},"Cache[K,V]",", обобщённые helpers. Reflect полезен, когда форма данных реально известна только в runtime, но за это платим сложностью, паниками и потерей compile-time проверок.",[7930,7931,7934,7937,8056],"predict",{"answer":63,"id":7932,"xp":7933},"advanced-generics-reflect-p1","15",[339,7935,7936],{},"Что выведет программа?",[7899,7938,7939],{"v-slot:code":5},[59,7940,7942],{"className":61,"code":7941,"language":63,"meta":5,"style":5},"package main\n\nimport \"fmt\"\n\nfunc First[T any](items []T) T {\n    return items[0]\n}\n\nfunc main() {\n    fmt.Println(First([]string{\"go\", \"reflect\"}))\n}\n",[65,7943,7944,7950,7954,7965,7969,7997,8008,8012,8016,8024,8052],{"__ignoreMap":5},[68,7945,7946,7948],{"class":70,"line":71},[68,7947,3895],{"class":81},[68,7949,3898],{"class":85},[68,7951,7952],{"class":70,"line":78},[68,7953,155],{"emptyLinePlaceholder":154},[68,7955,7956,7958,7961,7963],{"class":70,"line":115},[68,7957,3907],{"class":81},[68,7959,7960],{"class":1157}," \"",[68,7962,3918],{"class":85},[68,7964,3921],{"class":1157},[68,7966,7967],{"class":70,"line":136},[68,7968,155],{"emptyLinePlaceholder":154},[68,7970,7971,7973,7976,7978,7980,7982,7984,7987,7989,7991,7993,7995],{"class":70,"line":145},[68,7972,82],{"class":81},[68,7974,7975],{"class":85}," First",[68,7977,232],{"class":89},[68,7979,235],{"class":93},[68,7981,373],{"class":85},[68,7983,245],{"class":89},[68,7985,7986],{"class":93},"items",[68,7988,2127],{"class":89},[68,7990,235],{"class":85},[68,7992,106],{"class":89},[68,7994,235],{"class":85},[68,7996,112],{"class":89},[68,7998,7999,8001,8004,8006],{"class":70,"line":151},[68,8000,139],{"class":81},[68,8002,8003],{"class":89}," items[",[68,8005,2151],{"class":302},[68,8007,2870],{"class":89},[68,8009,8010],{"class":70,"line":158},[68,8011,148],{"class":89},[68,8013,8014],{"class":70,"line":184},[68,8015,155],{"emptyLinePlaceholder":154},[68,8017,8018,8020,8022],{"class":70,"line":199},[68,8019,82],{"class":81},[68,8021,3944],{"class":85},[68,8023,3947],{"class":89},[68,8025,8026,8028,8030,8032,8035,8037,8039,8041,8044,8046,8049],{"class":70,"line":206},[68,8027,4007],{"class":89},[68,8029,3136],{"class":85},[68,8031,90],{"class":89},[68,8033,8034],{"class":85},"First",[68,8036,5150],{"class":89},[68,8038,576],{"class":81},[68,8040,5015],{"class":89},[68,8042,8043],{"class":1157},"\"go\"",[68,8045,97],{"class":89},[68,8047,8048],{"class":1157},"\"reflect\"",[68,8050,8051],{"class":89},"}))\n",[68,8053,8054],{"class":70,"line":2425},[68,8055,148],{"class":89},[7899,8057,8058],{"v-slot:hint":5},[339,8059,8060,8061,8063,8064,8066,8067,8070],{},"Компилятор выводит ",[65,8062,235],{}," как ",[65,8065,576],{},", потому что аргумент — ",[65,8068,8069],{},"[]string",". Функция возвращает первый элемент слайса.",[8072,8073,8077,8087,8285],"code-task",{"expected":8074,"id":8075,"xp":8076},"2\\n4\\n6","advanced-generics-reflect-ct1","20",[339,8078,8079,8080,8082,8083,8086],{},"Реализуй обобщённую функцию ",[65,8081,7922],{},": она должна применить ",[65,8084,8085],{},"fn"," к каждому элементу входного слайса и вернуть новый слайс результатов.",[7899,8088,8089],{"v-slot:template":5},[59,8090,8092],{"className":61,"code":8091,"language":63,"meta":5,"style":5},"package main\n\nimport \"fmt\"\n\nfunc Map[T any, R any](items []T, fn func(T) R) []R {\n    return nil\n}\n\nfunc main() {\n    out := Map([]int{1, 2, 3}, func(n int) int {\n        return n * 2\n    })\n\n    for _, v := range out {\n        fmt.Println(v)\n    }\n}\n",[65,8093,8094,8100,8104,8114,8118,8167,8174,8178,8182,8190,8233,8246,8250,8254,8267,8277,8281],{"__ignoreMap":5},[68,8095,8096,8098],{"class":70,"line":71},[68,8097,3895],{"class":81},[68,8099,3898],{"class":85},[68,8101,8102],{"class":70,"line":78},[68,8103,155],{"emptyLinePlaceholder":154},[68,8105,8106,8108,8110,8112],{"class":70,"line":115},[68,8107,3907],{"class":81},[68,8109,7960],{"class":1157},[68,8111,3918],{"class":85},[68,8113,3921],{"class":1157},[68,8115,8116],{"class":70,"line":136},[68,8117,155],{"emptyLinePlaceholder":154},[68,8119,8120,8122,8125,8127,8129,8131,8133,8136,8138,8140,8142,8144,8146,8148,8150,8153,8155,8157,8159,8161,8163,8165],{"class":70,"line":145},[68,8121,82],{"class":81},[68,8123,8124],{"class":85}," Map",[68,8126,232],{"class":89},[68,8128,235],{"class":93},[68,8130,373],{"class":85},[68,8132,97],{"class":89},[68,8134,8135],{"class":93},"R",[68,8137,373],{"class":85},[68,8139,245],{"class":89},[68,8141,7986],{"class":93},[68,8143,2127],{"class":89},[68,8145,235],{"class":85},[68,8147,97],{"class":89},[68,8149,8085],{"class":93},[68,8151,8152],{"class":81}," func",[68,8154,90],{"class":89},[68,8156,235],{"class":85},[68,8158,106],{"class":89},[68,8160,8135],{"class":85},[68,8162,990],{"class":89},[68,8164,8135],{"class":85},[68,8166,112],{"class":89},[68,8168,8169,8171],{"class":70,"line":151},[68,8170,139],{"class":81},[68,8172,8173],{"class":302}," nil\n",[68,8175,8176],{"class":70,"line":158},[68,8177,148],{"class":89},[68,8179,8180],{"class":70,"line":184},[68,8181,155],{"emptyLinePlaceholder":154},[68,8183,8184,8186,8188],{"class":70,"line":199},[68,8185,82],{"class":81},[68,8187,3944],{"class":85},[68,8189,3947],{"class":89},[68,8191,8192,8195,8197,8199,8201,8203,8205,8207,8209,8211,8213,8215,8218,8220,8222,8225,8227,8229,8231],{"class":70,"line":206},[68,8193,8194],{"class":89},"    out ",[68,8196,2754],{"class":81},[68,8198,8124],{"class":85},[68,8200,5150],{"class":89},[68,8202,109],{"class":81},[68,8204,5015],{"class":89},[68,8206,303],{"class":302},[68,8208,97],{"class":89},[68,8210,308],{"class":302},[68,8212,97],{"class":89},[68,8214,3165],{"class":302},[68,8216,8217],{"class":89},"}, ",[68,8219,82],{"class":81},[68,8221,90],{"class":89},[68,8223,8224],{"class":93},"n",[68,8226,103],{"class":81},[68,8228,106],{"class":89},[68,8230,109],{"class":81},[68,8232,112],{"class":89},[68,8234,8235,8238,8241,8243],{"class":70,"line":2425},[68,8236,8237],{"class":81},"        return",[68,8239,8240],{"class":89}," n ",[68,8242,1192],{"class":81},[68,8244,8245],{"class":302}," 2\n",[68,8247,8248],{"class":70,"line":2437},[68,8249,5200],{"class":89},[68,8251,8252],{"class":70,"line":2449},[68,8253,155],{"emptyLinePlaceholder":154},[68,8255,8256,8258,8260,8262,8264],{"class":70,"line":2687},[68,8257,3122],{"class":81},[68,8259,3125],{"class":89},[68,8261,2754],{"class":81},[68,8263,3130],{"class":81},[68,8265,8266],{"class":89}," out {\n",[68,8268,8269,8272,8274],{"class":70,"line":2693},[68,8270,8271],{"class":89},"        fmt.",[68,8273,3136],{"class":85},[68,8275,8276],{"class":89},"(v)\n",[68,8278,8279],{"class":70,"line":2722},[68,8280,3580],{"class":89},[68,8282,8283],{"class":70,"line":2733},[68,8284,148],{"class":89},[7899,8286,8287],{"v-slot:hints":5},[11,8288,8289,8295,8304],{},[14,8290,8291,8292],{},"Создай ",[65,8293,8294],{},"out := make([]R, len(items))",[14,8296,8297,8298,8300,8301],{},"Пройди по ",[65,8299,7986],{}," через ",[65,8302,8303],{},"for i, item := range items",[14,8305,8306,8307,8310],{},"Пиши результат в ",[65,8308,8309],{},"out[i]",", чтобы сохранить порядок",[8312,8313,8314],"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 .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}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 .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}",{"title":5,"searchDepth":78,"depth":78,"links":8316},[8317,8357,8378,8400],{"id":47,"depth":78,"text":48,"children":8318},[8319,8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,8338,8339,8340,8341,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356],{"id":52,"depth":115,"text":53},{"id":56,"depth":115,"text":57},{"id":211,"depth":115,"text":212},{"id":344,"depth":115,"text":345},{"id":478,"depth":115,"text":479},{"id":482,"depth":115,"text":483},{"id":535,"depth":115,"text":536},{"id":606,"depth":115,"text":607},{"id":782,"depth":115,"text":783},{"id":942,"depth":115,"text":943},{"id":1074,"depth":115,"text":1075},{"id":1078,"depth":115,"text":1079},{"id":1167,"depth":115,"text":1168},{"id":1287,"depth":115,"text":1288},{"id":1365,"depth":115,"text":1366},{"id":1584,"depth":115,"text":1585},{"id":1588,"depth":115,"text":1589},{"id":1714,"depth":115,"text":1715},{"id":1785,"depth":115,"text":1786},{"id":1827,"depth":115,"text":1828},{"id":1934,"depth":115,"text":1935},{"id":2091,"depth":115,"text":2092},{"id":2178,"depth":115,"text":8342},"String + byte — только чтение",{"id":2313,"depth":115,"text":2314},{"id":2506,"depth":115,"text":2507},{"id":2510,"depth":115,"text":2511},{"id":2799,"depth":115,"text":2800},{"id":2936,"depth":115,"text":2937},{"id":2993,"depth":115,"text":2994},{"id":3086,"depth":115,"text":3087},{"id":3225,"depth":115,"text":3226},{"id":3420,"depth":115,"text":3421},{"id":3424,"depth":115,"text":3425},{"id":3594,"depth":115,"text":3595},{"id":3609,"depth":115,"text":3610},{"id":3714,"depth":115,"text":3715},{"id":3724,"depth":115,"text":3725},{"id":3795,"depth":78,"text":3796,"children":8358},[8359,8360,8361,8362,8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373,8374,8375,8376,8377],{"id":3799,"depth":115,"text":3800},{"id":3803,"depth":115,"text":3804},{"id":3884,"depth":115,"text":3885},{"id":4030,"depth":115,"text":4031},{"id":4263,"depth":115,"text":4264},{"id":4278,"depth":115,"text":4279},{"id":4458,"depth":115,"text":4459},{"id":4462,"depth":115,"text":4463},{"id":4708,"depth":115,"text":4709},{"id":4875,"depth":115,"text":4876},{"id":5231,"depth":115,"text":5232},{"id":5333,"depth":115,"text":5334},{"id":5473,"depth":115,"text":5474},{"id":5640,"depth":115,"text":5641},{"id":5644,"depth":115,"text":5645},{"id":5610,"depth":115,"text":5759},{"id":5834,"depth":115,"text":5616},{"id":5840,"depth":115,"text":5622},{"id":5846,"depth":115,"text":5847},{"id":5971,"depth":78,"text":5972,"children":8379},[8380,8381,8382,8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398,8399],{"id":5975,"depth":115,"text":5976},{"id":6157,"depth":115,"text":6158},{"id":6126,"depth":115,"text":6161},{"id":6240,"depth":115,"text":6241},{"id":6367,"depth":115,"text":6368},{"id":6494,"depth":115,"text":6495},{"id":6593,"depth":115,"text":6594},{"id":6669,"depth":115,"text":6670},{"id":6726,"depth":115,"text":6727},{"id":6730,"depth":115,"text":6731},{"id":6808,"depth":115,"text":6809},{"id":7022,"depth":115,"text":7023},{"id":7130,"depth":115,"text":7131},{"id":7246,"depth":115,"text":7247},{"id":7431,"depth":115,"text":7432},{"id":7435,"depth":115,"text":7436},{"id":7450,"depth":115,"text":7451},{"id":7552,"depth":115,"text":7553},{"id":7699,"depth":115,"text":7700},{"id":7824,"depth":115,"text":7825},{"id":7888,"depth":78,"text":7889},1781458311168]