[{"data":1,"prerenderedAt":5258},["ShallowReactive",2],{"content:\u002F01-basics\u002F05-interfaces":3},{"title":4,"description":5,"path":6,"body":7},"Интерфейсы в Go","Интерфейсы — это то, что делает Go-код по-настоящему гибким. В большинстве языков для реализации интерфейса нужно явно написать implements. В Go достаточно просто иметь нужные методы — это называется structural typing или duck typing. За этой простотой снаружи скрывается нетривиальное устройство внутри, которое важно понимать, чтобы не попасть в классические ловушки.","\u002F01-basics\u002F05-interfaces",{"type":8,"value":9,"toc":5237},"minimark",[10,15,29,32,37,283,286,289,343,346,348,352,359,372,422,434,438,555,583,595,597,601,633,701,703,707,710,846,853,868,870,874,882,910,1103,1132,1137,1303,1305,1309,1312,1469,1478,1480,1484,1487,1707,1713,1715,1719,1722,1746,1753,1756,1929,1931,1935,1939,1942,2073,2076,2080,2087,2290,2293,2297,2564,2566,2570,2582,2604,2627,2642,2662,2676,2690,2698,2706,2728,2730,2734,2736,2741,2747,2753,2777,2816,2821,2829,2834,3263,3265,3270,3275,3280,3285,3609,3614,3620,3624,3701,3703,3708,3713,3718,3739,3775,3779,3785,3789,4414,4416,4420,4459,4786,5233],[11,12,14],"h1",{"id":13},"интерфейс-в-go","Интерфейс в Go",[16,17,18,19,23,24,28],"p",{},"Интерфейсы — это то, что делает Go-код по-настоящему гибким. В большинстве языков для реализации интерфейса нужно явно написать ",[20,21,22],"code",{},"implements",". В Go достаточно просто иметь нужные методы — это называется ",[25,26,27],"strong",{},"structural typing"," или duck typing. За этой простотой снаружи скрывается нетривиальное устройство внутри, которое важно понимать, чтобы не попасть в классические ловушки.",[30,31],"hr",{},[33,34,36],"h2",{"id":35},"объявление-и-неявная-реализация","Объявление и неявная реализация",[38,39,44],"pre",{"className":40,"code":41,"language":42,"meta":43,"style":43},"language-go shiki shiki-themes github-dark","package main\n\nimport \"fmt\"\n\ntype Stringer interface {\n    String() string\n}\n\ntype User struct {\n    Name string\n}\n\n\u002F\u002F User реализует Stringer — просто наличием метода\n\u002F\u002F Никакого \"implements Stringer\" не нужно\nfunc (u User) String() string {\n    return u.Name\n}\n\nfunc main() {\n    var s Stringer = User{Name: \"Alice\"} \u002F\u002F работает\n    fmt.Println(s.String())              \u002F\u002F \"Alice\"\n}\n","go","",[20,45,46,59,66,82,87,103,115,121,126,139,147,152,157,164,170,199,208,213,218,229,258,278],{"__ignoreMap":43},[47,48,51,55],"span",{"class":49,"line":50},"line",1,[47,52,54],{"class":53},"snl16","package",[47,56,58],{"class":57},"svObZ"," main\n",[47,60,62],{"class":49,"line":61},2,[47,63,65],{"emptyLinePlaceholder":64},true,"\n",[47,67,69,72,76,79],{"class":49,"line":68},3,[47,70,71],{"class":53},"import",[47,73,75],{"class":74},"sU2Wk"," \"",[47,77,78],{"class":57},"fmt",[47,80,81],{"class":74},"\"\n",[47,83,85],{"class":49,"line":84},4,[47,86,65],{"emptyLinePlaceholder":64},[47,88,90,93,96,99],{"class":49,"line":89},5,[47,91,92],{"class":53},"type",[47,94,95],{"class":57}," Stringer",[47,97,98],{"class":53}," interface",[47,100,102],{"class":101},"s95oV"," {\n",[47,104,106,109,112],{"class":49,"line":105},6,[47,107,108],{"class":57},"    String",[47,110,111],{"class":101},"() ",[47,113,114],{"class":53},"string\n",[47,116,118],{"class":49,"line":117},7,[47,119,120],{"class":101},"}\n",[47,122,124],{"class":49,"line":123},8,[47,125,65],{"emptyLinePlaceholder":64},[47,127,129,131,134,137],{"class":49,"line":128},9,[47,130,92],{"class":53},[47,132,133],{"class":57}," User",[47,135,136],{"class":53}," struct",[47,138,102],{"class":101},[47,140,142,145],{"class":49,"line":141},10,[47,143,144],{"class":101},"    Name ",[47,146,114],{"class":53},[47,148,150],{"class":49,"line":149},11,[47,151,120],{"class":101},[47,153,155],{"class":49,"line":154},12,[47,156,65],{"emptyLinePlaceholder":64},[47,158,160],{"class":49,"line":159},13,[47,161,163],{"class":162},"sAwPA","\u002F\u002F User реализует Stringer — просто наличием метода\n",[47,165,167],{"class":49,"line":166},14,[47,168,169],{"class":162},"\u002F\u002F Никакого \"implements Stringer\" не нужно\n",[47,171,173,176,179,183,186,189,192,194,197],{"class":49,"line":172},15,[47,174,175],{"class":53},"func",[47,177,178],{"class":101}," (",[47,180,182],{"class":181},"s9osk","u ",[47,184,185],{"class":57},"User",[47,187,188],{"class":101},") ",[47,190,191],{"class":57},"String",[47,193,111],{"class":101},[47,195,196],{"class":53},"string",[47,198,102],{"class":101},[47,200,202,205],{"class":49,"line":201},16,[47,203,204],{"class":53},"    return",[47,206,207],{"class":101}," u.Name\n",[47,209,211],{"class":49,"line":210},17,[47,212,120],{"class":101},[47,214,216],{"class":49,"line":215},18,[47,217,65],{"emptyLinePlaceholder":64},[47,219,221,223,226],{"class":49,"line":220},19,[47,222,175],{"class":53},[47,224,225],{"class":57}," main",[47,227,228],{"class":101},"() {\n",[47,230,232,235,238,241,244,246,249,252,255],{"class":49,"line":231},20,[47,233,234],{"class":53},"    var",[47,236,237],{"class":101}," s ",[47,239,240],{"class":57},"Stringer",[47,242,243],{"class":53}," =",[47,245,133],{"class":57},[47,247,248],{"class":101},"{Name: ",[47,250,251],{"class":74},"\"Alice\"",[47,253,254],{"class":101},"} ",[47,256,257],{"class":162},"\u002F\u002F работает\n",[47,259,261,264,267,270,272,275],{"class":49,"line":260},21,[47,262,263],{"class":101},"    fmt.",[47,265,266],{"class":57},"Println",[47,268,269],{"class":101},"(s.",[47,271,191],{"class":57},[47,273,274],{"class":101},"())              ",[47,276,277],{"class":162},"\u002F\u002F \"Alice\"\n",[47,279,281],{"class":49,"line":280},22,[47,282,120],{"class":101},[16,284,285],{},"Компилятор проверяет соответствие интерфейсу в момент присвоения. Если метода нет — ошибка компиляции, а не рантайм.",[16,287,288],{},"Чтобы явно проверить реализацию во время компиляции — используют blank identifier:",[38,290,292],{"className":40,"code":291,"language":42,"meta":43,"style":43},"var _ Stringer = User{}     \u002F\u002F если User не реализует Stringer — ошибка компиляции\nvar _ Stringer = (*User)(nil) \u002F\u002F проверка для pointer receiver\n",[20,293,294,314],{"__ignoreMap":43},[47,295,296,299,302,304,306,308,311],{"class":49,"line":50},[47,297,298],{"class":53},"var",[47,300,301],{"class":101}," _ ",[47,303,240],{"class":57},[47,305,243],{"class":53},[47,307,133],{"class":57},[47,309,310],{"class":101},"{}     ",[47,312,313],{"class":162},"\u002F\u002F если User не реализует Stringer — ошибка компиляции\n",[47,315,316,318,320,322,324,326,329,331,334,338,340],{"class":49,"line":61},[47,317,298],{"class":53},[47,319,301],{"class":101},[47,321,240],{"class":57},[47,323,243],{"class":53},[47,325,178],{"class":101},[47,327,328],{"class":53},"*",[47,330,185],{"class":57},[47,332,333],{"class":101},")(",[47,335,337],{"class":336},"sDLfK","nil",[47,339,188],{"class":101},[47,341,342],{"class":162},"\u002F\u002F проверка для pointer receiver\n",[16,344,345],{},"Это идиоматичный способ зафиксировать намерение и получить ошибку сразу, а не в момент использования.",[30,347],{},[33,349,351],{"id":350},"внутреннее-устройство-iface-и-eface","Внутреннее устройство: iface и eface",[16,353,354,355,358],{},"Переменная интерфейсного типа — это не просто указатель на данные. Под капотом это ",[25,356,357],{},"два слова"," (два указателя по 8 байт на 64-битной платформе). Конкретная структура зависит от того, пустой интерфейс или нет.",[360,361,363,364,367,368,371],"h3",{"id":362},"eface-пустой-интерфейс-interface-any","eface — пустой интерфейс (",[20,365,366],{},"interface{}"," \u002F ",[20,369,370],{},"any",")",[38,373,375],{"className":40,"code":374,"language":42,"meta":43,"style":43},"type eface struct {\n    _type *_type  \u002F\u002F указатель на описание типа\n    data  unsafe.Pointer \u002F\u002F указатель на данные\n}\n",[20,376,377,388,401,418],{"__ignoreMap":43},[47,378,379,381,384,386],{"class":49,"line":50},[47,380,92],{"class":53},[47,382,383],{"class":57}," eface",[47,385,136],{"class":53},[47,387,102],{"class":101},[47,389,390,393,395,398],{"class":49,"line":61},[47,391,392],{"class":101},"    _type ",[47,394,328],{"class":53},[47,396,397],{"class":57},"_type",[47,399,400],{"class":162},"  \u002F\u002F указатель на описание типа\n",[47,402,403,406,409,412,415],{"class":49,"line":68},[47,404,405],{"class":101},"    data  ",[47,407,408],{"class":57},"unsafe",[47,410,411],{"class":101},".",[47,413,414],{"class":57},"Pointer",[47,416,417],{"class":162}," \u002F\u002F указатель на данные\n",[47,419,420],{"class":49,"line":84},[47,421,120],{"class":101},[16,423,424,427,428,430,431,433],{},[20,425,426],{},"eface"," используется для ",[20,429,366],{}," (он же ",[20,432,370],{}," начиная с Go 1.18). Хранит только тип и данные — никакой таблицы методов не нужно, потому что через пустой интерфейс методы не вызываются.",[360,435,437],{"id":436},"iface-непустой-интерфейс","iface — непустой интерфейс",[38,439,441],{"className":40,"code":440,"language":42,"meta":43,"style":43},"type iface struct {\n    tab  *itab          \u002F\u002F указатель на таблицу методов (itab)\n    data unsafe.Pointer \u002F\u002F указатель на данные\n}\n\ntype itab struct {\n    inter *interfacetype \u002F\u002F описание интерфейса\n    _type *_type         \u002F\u002F описание конкретного типа\n    hash  uint32         \u002F\u002F копия hash конкретного типа, используется в type switch\n    fun   [1]uintptr     \u002F\u002F таблица методов (variable size)\n}\n",[20,442,443,454,467,480,484,488,499,512,523,534,551],{"__ignoreMap":43},[47,444,445,447,450,452],{"class":49,"line":50},[47,446,92],{"class":53},[47,448,449],{"class":57}," iface",[47,451,136],{"class":53},[47,453,102],{"class":101},[47,455,456,459,461,464],{"class":49,"line":61},[47,457,458],{"class":101},"    tab  ",[47,460,328],{"class":53},[47,462,463],{"class":57},"itab",[47,465,466],{"class":162},"          \u002F\u002F указатель на таблицу методов (itab)\n",[47,468,469,472,474,476,478],{"class":49,"line":68},[47,470,471],{"class":101},"    data ",[47,473,408],{"class":57},[47,475,411],{"class":101},[47,477,414],{"class":57},[47,479,417],{"class":162},[47,481,482],{"class":49,"line":84},[47,483,120],{"class":101},[47,485,486],{"class":49,"line":89},[47,487,65],{"emptyLinePlaceholder":64},[47,489,490,492,495,497],{"class":49,"line":105},[47,491,92],{"class":53},[47,493,494],{"class":57}," itab",[47,496,136],{"class":53},[47,498,102],{"class":101},[47,500,501,504,506,509],{"class":49,"line":117},[47,502,503],{"class":101},"    inter ",[47,505,328],{"class":53},[47,507,508],{"class":57},"interfacetype",[47,510,511],{"class":162}," \u002F\u002F описание интерфейса\n",[47,513,514,516,518,520],{"class":49,"line":123},[47,515,392],{"class":101},[47,517,328],{"class":53},[47,519,397],{"class":57},[47,521,522],{"class":162},"         \u002F\u002F описание конкретного типа\n",[47,524,525,528,531],{"class":49,"line":128},[47,526,527],{"class":101},"    hash  ",[47,529,530],{"class":53},"uint32",[47,532,533],{"class":162},"         \u002F\u002F копия hash конкретного типа, используется в type switch\n",[47,535,536,539,542,545,548],{"class":49,"line":141},[47,537,538],{"class":101},"    fun   [",[47,540,541],{"class":336},"1",[47,543,544],{"class":101},"]",[47,546,547],{"class":53},"uintptr",[47,549,550],{"class":162},"     \u002F\u002F таблица методов (variable size)\n",[47,552,553],{"class":49,"line":149},[47,554,120],{"class":101},[16,556,557,560,561,563,564,567,568,571,572,575,576,579,580,411],{},[20,558,559],{},"iface"," используется для любого непустого интерфейса. ",[20,562,463],{}," — это кешируемая структура: Go не строит её заново при каждом присвоении, а хранит в глобальном кеше по паре ",[20,565,566],{},"(interface, concrete type)",". В реальном ",[20,569,570],{},"internal\u002Fabi.ITab"," поле называется ",[20,573,574],{},"Hash uint32",": это копия хэша конкретного типа, которую runtime использует, например, для ускорения type switch. В памяти после ",[20,577,578],{},"hash"," есть padding перед таблицей ",[20,581,582],{},"fun",[16,584,585,588,589,591,592,594],{},[25,586,587],{},"Главное различие в одну строку:"," ",[20,590,426],{}," — два слова (тип + данные), ",[20,593,559],{}," — два слова (itab + данные), где itab содержит и тип, и таблицу методов для диспетчеризации вызовов.",[30,596],{},[33,598,600],{"id":599},"как-данные-попадают-в-интерфейс","Как данные попадают в интерфейс",[16,602,603,604,607,608,611,612,611,615,611,618,611,620,623,624,611,627,629,630,632],{},"Поле ",[20,605,606],{},"data"," — одно машинное слово. Для некоторых типов, представимых одним указателем (",[20,609,610],{},"*T",", ",[20,613,614],{},"map",[20,616,617],{},"chan",[20,619,175],{},[20,621,622],{},"unsafe.Pointer"," и простые обертки над ними), значение хранится прямо в этом слове. Большинство обычных значений (",[20,625,626],{},"int",[20,628,196],{},", структуры) кладутся в отдельную копию, а ",[20,631,606],{}," хранит указатель на нее. Эта копия не обязана всегда быть в куче: место выбирает escape analysis. Но если интерфейсное значение уходит за пределы текущего вызова, упаковка может стать аллокацией.",[38,634,636],{"className":40,"code":635,"language":42,"meta":43,"style":43},"var s Stringer\n\n\u002F\u002F data указывает на копию User; если интерфейс escape'ится, копия может уйти в кучу\ns = User{Name: \"Alice\"}\n\n\u002F\u002F Для указателя data хранит сам pointer value\ns = &User{Name: \"Alice\"} \u002F\u002F литерал все равно может аллоцироваться, если указатель escape'ится\n",[20,637,638,647,651,656,672,676,681],{"__ignoreMap":43},[47,639,640,642,644],{"class":49,"line":50},[47,641,298],{"class":53},[47,643,237],{"class":101},[47,645,646],{"class":57},"Stringer\n",[47,648,649],{"class":49,"line":61},[47,650,65],{"emptyLinePlaceholder":64},[47,652,653],{"class":49,"line":68},[47,654,655],{"class":162},"\u002F\u002F data указывает на копию User; если интерфейс escape'ится, копия может уйти в кучу\n",[47,657,658,661,664,666,668,670],{"class":49,"line":84},[47,659,660],{"class":101},"s ",[47,662,663],{"class":53},"=",[47,665,133],{"class":57},[47,667,248],{"class":101},[47,669,251],{"class":74},[47,671,120],{"class":101},[47,673,674],{"class":49,"line":89},[47,675,65],{"emptyLinePlaceholder":64},[47,677,678],{"class":49,"line":105},[47,679,680],{"class":162},"\u002F\u002F Для указателя data хранит сам pointer value\n",[47,682,683,685,687,690,692,694,696,698],{"class":49,"line":117},[47,684,660],{"class":101},[47,686,663],{"class":53},[47,688,689],{"class":53}," &",[47,691,185],{"class":57},[47,693,248],{"class":101},[47,695,251],{"class":74},[47,697,254],{"class":101},[47,699,700],{"class":162},"\u002F\u002F литерал все равно может аллоцироваться, если указатель escape'ится\n",[30,702],{},[33,704,706],{"id":705},"composition-интерфейсы-из-интерфейсов","Composition — интерфейсы из интерфейсов",[16,708,709],{},"Интерфейсы можно компоновать из других интерфейсов:",[38,711,713],{"className":40,"code":712,"language":42,"meta":43,"style":43},"type Reader interface {\n    Read(p []byte) (n int, err error)\n}\n\ntype Writer interface {\n    Write(p []byte) (n int, err error)\n}\n\n\u002F\u002F io.ReadWriter — стандартный пример из stdlib\ntype ReadWriter interface {\n    Reader\n    Writer\n}\n",[20,714,715,726,762,766,770,781,808,812,816,821,832,837,842],{"__ignoreMap":43},[47,716,717,719,722,724],{"class":49,"line":50},[47,718,92],{"class":53},[47,720,721],{"class":57}," Reader",[47,723,98],{"class":53},[47,725,102],{"class":101},[47,727,728,731,734,736,739,742,745,748,751,753,756,759],{"class":49,"line":61},[47,729,730],{"class":57},"    Read",[47,732,733],{"class":101},"(",[47,735,16],{"class":181},[47,737,738],{"class":101}," []",[47,740,741],{"class":53},"byte",[47,743,744],{"class":101},") (",[47,746,747],{"class":181},"n",[47,749,750],{"class":53}," int",[47,752,611],{"class":101},[47,754,755],{"class":181},"err",[47,757,758],{"class":53}," error",[47,760,761],{"class":101},")\n",[47,763,764],{"class":49,"line":68},[47,765,120],{"class":101},[47,767,768],{"class":49,"line":84},[47,769,65],{"emptyLinePlaceholder":64},[47,771,772,774,777,779],{"class":49,"line":89},[47,773,92],{"class":53},[47,775,776],{"class":57}," Writer",[47,778,98],{"class":53},[47,780,102],{"class":101},[47,782,783,786,788,790,792,794,796,798,800,802,804,806],{"class":49,"line":105},[47,784,785],{"class":57},"    Write",[47,787,733],{"class":101},[47,789,16],{"class":181},[47,791,738],{"class":101},[47,793,741],{"class":53},[47,795,744],{"class":101},[47,797,747],{"class":181},[47,799,750],{"class":53},[47,801,611],{"class":101},[47,803,755],{"class":181},[47,805,758],{"class":53},[47,807,761],{"class":101},[47,809,810],{"class":49,"line":117},[47,811,120],{"class":101},[47,813,814],{"class":49,"line":123},[47,815,65],{"emptyLinePlaceholder":64},[47,817,818],{"class":49,"line":128},[47,819,820],{"class":162},"\u002F\u002F io.ReadWriter — стандартный пример из stdlib\n",[47,822,823,825,828,830],{"class":49,"line":141},[47,824,92],{"class":53},[47,826,827],{"class":57}," ReadWriter",[47,829,98],{"class":53},[47,831,102],{"class":101},[47,833,834],{"class":49,"line":149},[47,835,836],{"class":57},"    Reader\n",[47,838,839],{"class":49,"line":154},[47,840,841],{"class":57},"    Writer\n",[47,843,844],{"class":49,"line":159},[47,845,120],{"class":101},[16,847,848,849,852],{},"Тип, реализующий ",[20,850,851],{},"ReadWriter",", должен иметь оба метода. Это основа модульности в Go: маленькие интерфейсы из одного-двух методов, которые собираются в более крупные по необходимости.",[854,855,856],"blockquote",{},[16,857,858,859,863,864,867],{},"Знаменитая цитата из Go-сообщества: ",[860,861,862],"em",{},"\"The bigger the interface, the weaker the abstraction\""," — Роб Пайк. ",[20,865,866],{},"io.Reader"," с одним методом применим в тысячах мест. Интерфейс из 15 методов — почти нигде.",[30,869],{},[33,871,873],{"id":872},"nil-interface-главная-ловушка","nil interface — главная ловушка",[16,875,876,877,879,880,411],{},"Это одна из самых известных ловушек в Go, и она прямо следует из устройства ",[20,878,559],{},"\u002F",[20,881,426],{},[16,883,884,885,887,888,178,891,879,894,896,897,899,900,902,903,905,906,909],{},"Интерфейс равен ",[20,886,337],{}," только если ",[25,889,890],{},"оба поля",[20,892,893],{},"tab",[20,895,397],{}," и ",[20,898,606],{},") равны ",[20,901,337],{},". Если тип задан, а данные ",[20,904,337],{}," — интерфейс ",[25,907,908],{},"не nil",":",[38,911,913],{"className":40,"code":912,"language":42,"meta":43,"style":43},"package main\n\nimport \"fmt\"\n\ntype MyError struct{ msg string }\n\nfunc (e *MyError) Error() string { return e.msg }\n\nfunc getError() error {\n    var p *MyError = nil \u002F\u002F typed nil pointer\n    return p             \u002F\u002F УПАКОВЫВАЕТСЯ в iface: tab=*MyError, data=nil\n}\n\nfunc main() {\n    err := getError()\n    fmt.Println(err == nil) \u002F\u002F false (!!)\n    fmt.Println(err)        \u002F\u002F \u003Cnil> — выглядит как nil, но не nil\n}\n",[20,914,915,921,925,935,939,956,960,992,996,1010,1029,1039,1043,1047,1055,1068,1087,1099],{"__ignoreMap":43},[47,916,917,919],{"class":49,"line":50},[47,918,54],{"class":53},[47,920,58],{"class":57},[47,922,923],{"class":49,"line":61},[47,924,65],{"emptyLinePlaceholder":64},[47,926,927,929,931,933],{"class":49,"line":68},[47,928,71],{"class":53},[47,930,75],{"class":74},[47,932,78],{"class":57},[47,934,81],{"class":74},[47,936,937],{"class":49,"line":84},[47,938,65],{"emptyLinePlaceholder":64},[47,940,941,943,946,948,951,953],{"class":49,"line":89},[47,942,92],{"class":53},[47,944,945],{"class":57}," MyError",[47,947,136],{"class":53},[47,949,950],{"class":101},"{ msg ",[47,952,196],{"class":53},[47,954,955],{"class":101}," }\n",[47,957,958],{"class":49,"line":105},[47,959,65],{"emptyLinePlaceholder":64},[47,961,962,964,966,969,971,974,976,979,981,983,986,989],{"class":49,"line":117},[47,963,175],{"class":53},[47,965,178],{"class":101},[47,967,968],{"class":181},"e ",[47,970,328],{"class":53},[47,972,973],{"class":57},"MyError",[47,975,188],{"class":101},[47,977,978],{"class":57},"Error",[47,980,111],{"class":101},[47,982,196],{"class":53},[47,984,985],{"class":101}," { ",[47,987,988],{"class":53},"return",[47,990,991],{"class":101}," e.msg }\n",[47,993,994],{"class":49,"line":123},[47,995,65],{"emptyLinePlaceholder":64},[47,997,998,1000,1003,1005,1008],{"class":49,"line":128},[47,999,175],{"class":53},[47,1001,1002],{"class":57}," getError",[47,1004,111],{"class":101},[47,1006,1007],{"class":53},"error",[47,1009,102],{"class":101},[47,1011,1012,1014,1017,1019,1021,1023,1026],{"class":49,"line":141},[47,1013,234],{"class":53},[47,1015,1016],{"class":101}," p ",[47,1018,328],{"class":53},[47,1020,973],{"class":57},[47,1022,243],{"class":53},[47,1024,1025],{"class":336}," nil",[47,1027,1028],{"class":162}," \u002F\u002F typed nil pointer\n",[47,1030,1031,1033,1036],{"class":49,"line":149},[47,1032,204],{"class":53},[47,1034,1035],{"class":101}," p             ",[47,1037,1038],{"class":162},"\u002F\u002F УПАКОВЫВАЕТСЯ в iface: tab=*MyError, data=nil\n",[47,1040,1041],{"class":49,"line":154},[47,1042,120],{"class":101},[47,1044,1045],{"class":49,"line":159},[47,1046,65],{"emptyLinePlaceholder":64},[47,1048,1049,1051,1053],{"class":49,"line":166},[47,1050,175],{"class":53},[47,1052,225],{"class":57},[47,1054,228],{"class":101},[47,1056,1057,1060,1063,1065],{"class":49,"line":172},[47,1058,1059],{"class":101},"    err ",[47,1061,1062],{"class":53},":=",[47,1064,1002],{"class":57},[47,1066,1067],{"class":101},"()\n",[47,1069,1070,1072,1074,1077,1080,1082,1084],{"class":49,"line":201},[47,1071,263],{"class":101},[47,1073,266],{"class":57},[47,1075,1076],{"class":101},"(err ",[47,1078,1079],{"class":53},"==",[47,1081,1025],{"class":336},[47,1083,188],{"class":101},[47,1085,1086],{"class":162},"\u002F\u002F false (!!)\n",[47,1088,1089,1091,1093,1096],{"class":49,"line":210},[47,1090,263],{"class":101},[47,1092,266],{"class":57},[47,1094,1095],{"class":101},"(err)        ",[47,1097,1098],{"class":162},"\u002F\u002F \u003Cnil> — выглядит как nil, но не nil\n",[47,1100,1101],{"class":49,"line":215},[47,1102,120],{"class":101},[16,1104,1105,1106,1108,1109,1112,1113,1115,1116,1118,1119,1121,1122,1124,1125,1127,1128,1131],{},"Что происходит: ",[20,1107,16],{}," — это ",[20,1110,1111],{},"*MyError"," со значением ",[20,1114,337],{},". При возврате через ",[20,1117,1007],{}," (интерфейс) Go создаёт ",[20,1120,559],{}," с ",[20,1123,893],{},", указывающим на ",[20,1126,1111],{},", и ",[20,1129,1130],{},"data=nil",". Интерфейс ненулевой, потому что тип задан.",[16,1133,1134],{},[25,1135,1136],{},"Правильный способ вернуть nil error:",[38,1138,1140],{"className":40,"code":1139,"language":42,"meta":43,"style":43},"\u002F\u002F Плохо\nfunc validate(s string) error {\n    var err *ValidationError\n    if s == \"\" {\n        err = &ValidationError{\"empty\"}\n    }\n    return err \u002F\u002F всегда ненулевой error!\n}\n\n\u002F\u002F Хорошо\nfunc validate(s string) error {\n    if s == \"\" {\n        return &ValidationError{\"empty\"}\n    }\n    return nil \u002F\u002F возвращаем nil интерфейс, не typed nil\n}\n",[20,1141,1142,1147,1168,1180,1194,1214,1219,1228,1232,1236,1241,1259,1271,1286,1290,1299],{"__ignoreMap":43},[47,1143,1144],{"class":49,"line":50},[47,1145,1146],{"class":162},"\u002F\u002F Плохо\n",[47,1148,1149,1151,1154,1156,1159,1162,1164,1166],{"class":49,"line":61},[47,1150,175],{"class":53},[47,1152,1153],{"class":57}," validate",[47,1155,733],{"class":101},[47,1157,1158],{"class":181},"s",[47,1160,1161],{"class":53}," string",[47,1163,188],{"class":101},[47,1165,1007],{"class":53},[47,1167,102],{"class":101},[47,1169,1170,1172,1175,1177],{"class":49,"line":68},[47,1171,234],{"class":53},[47,1173,1174],{"class":101}," err ",[47,1176,328],{"class":53},[47,1178,1179],{"class":57},"ValidationError\n",[47,1181,1182,1185,1187,1189,1192],{"class":49,"line":84},[47,1183,1184],{"class":53},"    if",[47,1186,237],{"class":101},[47,1188,1079],{"class":53},[47,1190,1191],{"class":74}," \"\"",[47,1193,102],{"class":101},[47,1195,1196,1199,1201,1203,1206,1209,1212],{"class":49,"line":89},[47,1197,1198],{"class":101},"        err ",[47,1200,663],{"class":53},[47,1202,689],{"class":53},[47,1204,1205],{"class":57},"ValidationError",[47,1207,1208],{"class":101},"{",[47,1210,1211],{"class":74},"\"empty\"",[47,1213,120],{"class":101},[47,1215,1216],{"class":49,"line":105},[47,1217,1218],{"class":101},"    }\n",[47,1220,1221,1223,1225],{"class":49,"line":117},[47,1222,204],{"class":53},[47,1224,1174],{"class":101},[47,1226,1227],{"class":162},"\u002F\u002F всегда ненулевой error!\n",[47,1229,1230],{"class":49,"line":123},[47,1231,120],{"class":101},[47,1233,1234],{"class":49,"line":128},[47,1235,65],{"emptyLinePlaceholder":64},[47,1237,1238],{"class":49,"line":141},[47,1239,1240],{"class":162},"\u002F\u002F Хорошо\n",[47,1242,1243,1245,1247,1249,1251,1253,1255,1257],{"class":49,"line":149},[47,1244,175],{"class":53},[47,1246,1153],{"class":57},[47,1248,733],{"class":101},[47,1250,1158],{"class":181},[47,1252,1161],{"class":53},[47,1254,188],{"class":101},[47,1256,1007],{"class":53},[47,1258,102],{"class":101},[47,1260,1261,1263,1265,1267,1269],{"class":49,"line":154},[47,1262,1184],{"class":53},[47,1264,237],{"class":101},[47,1266,1079],{"class":53},[47,1268,1191],{"class":74},[47,1270,102],{"class":101},[47,1272,1273,1276,1278,1280,1282,1284],{"class":49,"line":159},[47,1274,1275],{"class":53},"        return",[47,1277,689],{"class":53},[47,1279,1205],{"class":57},[47,1281,1208],{"class":101},[47,1283,1211],{"class":74},[47,1285,120],{"class":101},[47,1287,1288],{"class":49,"line":166},[47,1289,1218],{"class":101},[47,1291,1292,1294,1296],{"class":49,"line":172},[47,1293,204],{"class":53},[47,1295,1025],{"class":336},[47,1297,1298],{"class":162}," \u002F\u002F возвращаем nil интерфейс, не typed nil\n",[47,1300,1301],{"class":49,"line":201},[47,1302,120],{"class":101},[30,1304],{},[33,1306,1308],{"id":1307},"type-assertion","Type assertion",[16,1310,1311],{},"Type assertion — это способ достать конкретный тип из интерфейса:",[38,1313,1315],{"className":40,"code":1314,"language":42,"meta":43,"style":43},"var s Stringer = User{Name: \"Alice\"}\n\n\u002F\u002F Одноаргументная форма — паника если тип не совпал\nu := s.(User)\n_ = u.Name \u002F\u002F \"Alice\"\n\n\u002F\u002F Двухаргументная форма — безопасно\nu2, ok := s.(User)\nif ok {\n    _ = u2.Name\n}\n\n\u002F\u002F Частая ошибка: assertion к неправильному типу\nvar s2 Stringer = User{Name: \"Alice\"}\n_, ok2 := s2.(*User) \u002F\u002F false — s содержит User, не *User\n_ = ok2\n",[20,1316,1317,1335,1339,1344,1357,1369,1373,1378,1391,1399,1409,1413,1417,1422,1441,1460],{"__ignoreMap":43},[47,1318,1319,1321,1323,1325,1327,1329,1331,1333],{"class":49,"line":50},[47,1320,298],{"class":53},[47,1322,237],{"class":101},[47,1324,240],{"class":57},[47,1326,243],{"class":53},[47,1328,133],{"class":57},[47,1330,248],{"class":101},[47,1332,251],{"class":74},[47,1334,120],{"class":101},[47,1336,1337],{"class":49,"line":61},[47,1338,65],{"emptyLinePlaceholder":64},[47,1340,1341],{"class":49,"line":68},[47,1342,1343],{"class":162},"\u002F\u002F Одноаргументная форма — паника если тип не совпал\n",[47,1345,1346,1348,1350,1353,1355],{"class":49,"line":84},[47,1347,182],{"class":101},[47,1349,1062],{"class":53},[47,1351,1352],{"class":101}," s.(",[47,1354,185],{"class":57},[47,1356,761],{"class":101},[47,1358,1359,1362,1364,1367],{"class":49,"line":89},[47,1360,1361],{"class":101},"_ ",[47,1363,663],{"class":53},[47,1365,1366],{"class":101}," u.Name ",[47,1368,277],{"class":162},[47,1370,1371],{"class":49,"line":105},[47,1372,65],{"emptyLinePlaceholder":64},[47,1374,1375],{"class":49,"line":117},[47,1376,1377],{"class":162},"\u002F\u002F Двухаргументная форма — безопасно\n",[47,1379,1380,1383,1385,1387,1389],{"class":49,"line":123},[47,1381,1382],{"class":101},"u2, ok ",[47,1384,1062],{"class":53},[47,1386,1352],{"class":101},[47,1388,185],{"class":57},[47,1390,761],{"class":101},[47,1392,1393,1396],{"class":49,"line":128},[47,1394,1395],{"class":53},"if",[47,1397,1398],{"class":101}," ok {\n",[47,1400,1401,1404,1406],{"class":49,"line":141},[47,1402,1403],{"class":101},"    _ ",[47,1405,663],{"class":53},[47,1407,1408],{"class":101}," u2.Name\n",[47,1410,1411],{"class":49,"line":149},[47,1412,120],{"class":101},[47,1414,1415],{"class":49,"line":154},[47,1416,65],{"emptyLinePlaceholder":64},[47,1418,1419],{"class":49,"line":159},[47,1420,1421],{"class":162},"\u002F\u002F Частая ошибка: assertion к неправильному типу\n",[47,1423,1424,1426,1429,1431,1433,1435,1437,1439],{"class":49,"line":166},[47,1425,298],{"class":53},[47,1427,1428],{"class":101}," s2 ",[47,1430,240],{"class":57},[47,1432,243],{"class":53},[47,1434,133],{"class":57},[47,1436,248],{"class":101},[47,1438,251],{"class":74},[47,1440,120],{"class":101},[47,1442,1443,1446,1448,1451,1453,1455,1457],{"class":49,"line":172},[47,1444,1445],{"class":101},"_, ok2 ",[47,1447,1062],{"class":53},[47,1449,1450],{"class":101}," s2.(",[47,1452,328],{"class":53},[47,1454,185],{"class":57},[47,1456,188],{"class":101},[47,1458,1459],{"class":162},"\u002F\u002F false — s содержит User, не *User\n",[47,1461,1462,1464,1466],{"class":49,"line":201},[47,1463,1361],{"class":101},[47,1465,663],{"class":53},[47,1467,1468],{"class":101}," ok2\n",[16,1470,1471,1472,1474,1475,1477],{},"Type assertion работает за O(1): Go сравнивает указатель на ",[20,1473,463],{}," в ",[20,1476,559],{}," с ожидаемым — это одно сравнение указателей.",[30,1479],{},[33,1481,1483],{"id":1482},"type-switch","Type switch",[16,1485,1486],{},"Когда нужно обработать несколько возможных типов — используют type switch:",[38,1488,1490],{"className":40,"code":1489,"language":42,"meta":43,"style":43},"func describe(i interface{}) string {\n    switch v := i.(type) {\n    case int:\n        return fmt.Sprintf(\"int: %d\", v)\n    case string:\n        return fmt.Sprintf(\"string: %q\", v)\n    case bool:\n        return fmt.Sprintf(\"bool: %v\", v)\n    case []int:\n        return fmt.Sprintf(\"[]int с длиной %d\", len(v))\n    case nil:\n        return \"nil\"\n    default:\n        return fmt.Sprintf(\"неизвестный тип: %T\", v)\n    }\n}\n",[20,1491,1492,1513,1531,1541,1565,1573,1593,1602,1622,1632,1657,1665,1672,1679,1699,1703],{"__ignoreMap":43},[47,1493,1494,1496,1499,1501,1504,1506,1509,1511],{"class":49,"line":50},[47,1495,175],{"class":53},[47,1497,1498],{"class":57}," describe",[47,1500,733],{"class":101},[47,1502,1503],{"class":181},"i",[47,1505,98],{"class":53},[47,1507,1508],{"class":101},"{}) ",[47,1510,196],{"class":53},[47,1512,102],{"class":101},[47,1514,1515,1518,1521,1523,1526,1528],{"class":49,"line":61},[47,1516,1517],{"class":53},"    switch",[47,1519,1520],{"class":101}," v ",[47,1522,1062],{"class":53},[47,1524,1525],{"class":101}," i.(",[47,1527,92],{"class":53},[47,1529,1530],{"class":101},") {\n",[47,1532,1533,1536,1538],{"class":49,"line":68},[47,1534,1535],{"class":53},"    case",[47,1537,750],{"class":53},[47,1539,1540],{"class":101},":\n",[47,1542,1543,1545,1548,1551,1553,1556,1559,1562],{"class":49,"line":84},[47,1544,1275],{"class":53},[47,1546,1547],{"class":101}," fmt.",[47,1549,1550],{"class":57},"Sprintf",[47,1552,733],{"class":101},[47,1554,1555],{"class":74},"\"int: ",[47,1557,1558],{"class":336},"%d",[47,1560,1561],{"class":74},"\"",[47,1563,1564],{"class":101},", v)\n",[47,1566,1567,1569,1571],{"class":49,"line":89},[47,1568,1535],{"class":53},[47,1570,1161],{"class":53},[47,1572,1540],{"class":101},[47,1574,1575,1577,1579,1581,1583,1586,1589,1591],{"class":49,"line":105},[47,1576,1275],{"class":53},[47,1578,1547],{"class":101},[47,1580,1550],{"class":57},[47,1582,733],{"class":101},[47,1584,1585],{"class":74},"\"string: ",[47,1587,1588],{"class":336},"%q",[47,1590,1561],{"class":74},[47,1592,1564],{"class":101},[47,1594,1595,1597,1600],{"class":49,"line":117},[47,1596,1535],{"class":53},[47,1598,1599],{"class":53}," bool",[47,1601,1540],{"class":101},[47,1603,1604,1606,1608,1610,1612,1615,1618,1620],{"class":49,"line":123},[47,1605,1275],{"class":53},[47,1607,1547],{"class":101},[47,1609,1550],{"class":57},[47,1611,733],{"class":101},[47,1613,1614],{"class":74},"\"bool: ",[47,1616,1617],{"class":336},"%v",[47,1619,1561],{"class":74},[47,1621,1564],{"class":101},[47,1623,1624,1626,1628,1630],{"class":49,"line":128},[47,1625,1535],{"class":53},[47,1627,738],{"class":101},[47,1629,626],{"class":53},[47,1631,1540],{"class":101},[47,1633,1634,1636,1638,1640,1642,1645,1647,1649,1651,1654],{"class":49,"line":141},[47,1635,1275],{"class":53},[47,1637,1547],{"class":101},[47,1639,1550],{"class":57},[47,1641,733],{"class":101},[47,1643,1644],{"class":74},"\"[]int с длиной ",[47,1646,1558],{"class":336},[47,1648,1561],{"class":74},[47,1650,611],{"class":101},[47,1652,1653],{"class":57},"len",[47,1655,1656],{"class":101},"(v))\n",[47,1658,1659,1661,1663],{"class":49,"line":149},[47,1660,1535],{"class":53},[47,1662,1025],{"class":336},[47,1664,1540],{"class":101},[47,1666,1667,1669],{"class":49,"line":154},[47,1668,1275],{"class":53},[47,1670,1671],{"class":74}," \"nil\"\n",[47,1673,1674,1677],{"class":49,"line":159},[47,1675,1676],{"class":53},"    default",[47,1678,1540],{"class":101},[47,1680,1681,1683,1685,1687,1689,1692,1695,1697],{"class":49,"line":166},[47,1682,1275],{"class":53},[47,1684,1547],{"class":101},[47,1686,1550],{"class":57},[47,1688,733],{"class":101},[47,1690,1691],{"class":74},"\"неизвестный тип: ",[47,1693,1694],{"class":336},"%T",[47,1696,1561],{"class":74},[47,1698,1564],{"class":101},[47,1700,1701],{"class":49,"line":172},[47,1702,1218],{"class":101},[47,1704,1705],{"class":49,"line":201},[47,1706,120],{"class":101},[16,1708,1709,1712],{},[20,1710,1711],{},"v"," в каждой ветке имеет конкретный тип, а не интерфейсный — компилятор это знает и позволяет обращаться к методам без дополнительных assertion.",[30,1714],{},[33,1716,1718],{"id":1717},"интерфейсы-и-производительность","Интерфейсы и производительность",[16,1720,1721],{},"Вызов метода через интерфейс дороже прямого вызова:",[1723,1724,1725,1734,1739,1743],"ol",{},[1726,1727,1728,1729,1731,1732],"li",{},"Загружаем ",[20,1730,463],{}," из ",[20,1733,559],{},[1726,1735,1736,1737],{},"Ищем нужный метод в таблице ",[20,1738,582],{},[1726,1740,1728,1741],{},[20,1742,606],{},[1726,1744,1745],{},"Вызываем",[16,1747,1748,1749,1752],{},"Это называется ",[25,1750,1751],{},"dynamic dispatch"," — диспетчеризация в рантайме. Компилятор не может заинлайнить вызов через интерфейс (в большинстве случаев), потому что не знает конкретный тип на этапе компиляции.",[16,1754,1755],{},"На практике это редко узкое место — разница в единицы наносекунд. Но в очень горячих путях (миллионы вызовов в секунду) конкретный тип вместо интерфейса может дать ощутимый прирост.",[38,1757,1759],{"className":40,"code":1758,"language":42,"meta":43,"style":43},"\u002F\u002F Медленнее в hot path: dynamic dispatch\nfunc sumInterface(items []Summable) int {\n    total := 0\n    for _, item := range items {\n        total += item.Sum() \u002F\u002F indirect call через itab\n    }\n    return total\n}\n\n\u002F\u002F Быстрее: конкретный тип, компилятор может инлайнить\nfunc sumConcrete(items []MyType) int {\n    total := 0\n    for _, item := range items {\n        total += item.Sum() \u002F\u002F direct call, возможен инлайнинг\n    }\n    return total\n}\n",[20,1760,1761,1766,1789,1799,1815,1834,1838,1845,1849,1853,1858,1880,1888,1900,1915,1919,1925],{"__ignoreMap":43},[47,1762,1763],{"class":49,"line":50},[47,1764,1765],{"class":162},"\u002F\u002F Медленнее в hot path: dynamic dispatch\n",[47,1767,1768,1770,1773,1775,1778,1780,1783,1785,1787],{"class":49,"line":61},[47,1769,175],{"class":53},[47,1771,1772],{"class":57}," sumInterface",[47,1774,733],{"class":101},[47,1776,1777],{"class":181},"items",[47,1779,738],{"class":101},[47,1781,1782],{"class":57},"Summable",[47,1784,188],{"class":101},[47,1786,626],{"class":53},[47,1788,102],{"class":101},[47,1790,1791,1794,1796],{"class":49,"line":68},[47,1792,1793],{"class":101},"    total ",[47,1795,1062],{"class":53},[47,1797,1798],{"class":336}," 0\n",[47,1800,1801,1804,1807,1809,1812],{"class":49,"line":84},[47,1802,1803],{"class":53},"    for",[47,1805,1806],{"class":101}," _, item ",[47,1808,1062],{"class":53},[47,1810,1811],{"class":53}," range",[47,1813,1814],{"class":101}," items {\n",[47,1816,1817,1820,1823,1826,1829,1831],{"class":49,"line":89},[47,1818,1819],{"class":101},"        total ",[47,1821,1822],{"class":53},"+=",[47,1824,1825],{"class":101}," item.",[47,1827,1828],{"class":57},"Sum",[47,1830,111],{"class":101},[47,1832,1833],{"class":162},"\u002F\u002F indirect call через itab\n",[47,1835,1836],{"class":49,"line":105},[47,1837,1218],{"class":101},[47,1839,1840,1842],{"class":49,"line":117},[47,1841,204],{"class":53},[47,1843,1844],{"class":101}," total\n",[47,1846,1847],{"class":49,"line":123},[47,1848,120],{"class":101},[47,1850,1851],{"class":49,"line":128},[47,1852,65],{"emptyLinePlaceholder":64},[47,1854,1855],{"class":49,"line":141},[47,1856,1857],{"class":162},"\u002F\u002F Быстрее: конкретный тип, компилятор может инлайнить\n",[47,1859,1860,1862,1865,1867,1869,1871,1874,1876,1878],{"class":49,"line":149},[47,1861,175],{"class":53},[47,1863,1864],{"class":57}," sumConcrete",[47,1866,733],{"class":101},[47,1868,1777],{"class":181},[47,1870,738],{"class":101},[47,1872,1873],{"class":57},"MyType",[47,1875,188],{"class":101},[47,1877,626],{"class":53},[47,1879,102],{"class":101},[47,1881,1882,1884,1886],{"class":49,"line":154},[47,1883,1793],{"class":101},[47,1885,1062],{"class":53},[47,1887,1798],{"class":336},[47,1889,1890,1892,1894,1896,1898],{"class":49,"line":159},[47,1891,1803],{"class":53},[47,1893,1806],{"class":101},[47,1895,1062],{"class":53},[47,1897,1811],{"class":53},[47,1899,1814],{"class":101},[47,1901,1902,1904,1906,1908,1910,1912],{"class":49,"line":166},[47,1903,1819],{"class":101},[47,1905,1822],{"class":53},[47,1907,1825],{"class":101},[47,1909,1828],{"class":57},[47,1911,111],{"class":101},[47,1913,1914],{"class":162},"\u002F\u002F direct call, возможен инлайнинг\n",[47,1916,1917],{"class":49,"line":172},[47,1918,1218],{"class":101},[47,1920,1921,1923],{"class":49,"line":201},[47,1922,204],{"class":53},[47,1924,1844],{"class":101},[47,1926,1927],{"class":49,"line":210},[47,1928,120],{"class":101},[30,1930],{},[33,1932,1934],{"id":1933},"паттерны-работы-с-интерфейсами","Паттерны работы с интерфейсами",[360,1936,1938],{"id":1937},"accept-interfaces-return-structs","Accept interfaces, return structs",[16,1940,1941],{},"Классический Go-принцип: функции принимают интерфейсы (гибкость), возвращают конкретные типы (ясность):",[38,1943,1945],{"className":40,"code":1944,"language":42,"meta":43,"style":43},"\u002F\u002F Хорошо: принимает io.Reader — работает с файлом, сетью, буфером, чем угодно\nfunc ParseConfig(r io.Reader) (*Config, error) {\n    \u002F\u002F ...\n}\n\n\u002F\u002F Плохо: возвращать интерфейс — скрывает реальный тип, затрудняет использование\nfunc NewStorage() Storage { \u002F\u002F интерфейс\n    return &RedisStorage{}\n}\n\n\u002F\u002F Хорошо: возвращать конкретный тип\nfunc NewStorage() *RedisStorage {\n    return &RedisStorage{}\n}\n",[20,1946,1947,1952,1985,1990,1994,1998,2003,2020,2032,2036,2040,2045,2059,2069],{"__ignoreMap":43},[47,1948,1949],{"class":49,"line":50},[47,1950,1951],{"class":162},"\u002F\u002F Хорошо: принимает io.Reader — работает с файлом, сетью, буфером, чем угодно\n",[47,1953,1954,1956,1959,1961,1964,1967,1969,1972,1974,1976,1979,1981,1983],{"class":49,"line":61},[47,1955,175],{"class":53},[47,1957,1958],{"class":57}," ParseConfig",[47,1960,733],{"class":101},[47,1962,1963],{"class":181},"r",[47,1965,1966],{"class":57}," io",[47,1968,411],{"class":101},[47,1970,1971],{"class":57},"Reader",[47,1973,744],{"class":101},[47,1975,328],{"class":53},[47,1977,1978],{"class":57},"Config",[47,1980,611],{"class":101},[47,1982,1007],{"class":53},[47,1984,1530],{"class":101},[47,1986,1987],{"class":49,"line":68},[47,1988,1989],{"class":162},"    \u002F\u002F ...\n",[47,1991,1992],{"class":49,"line":84},[47,1993,120],{"class":101},[47,1995,1996],{"class":49,"line":89},[47,1997,65],{"emptyLinePlaceholder":64},[47,1999,2000],{"class":49,"line":105},[47,2001,2002],{"class":162},"\u002F\u002F Плохо: возвращать интерфейс — скрывает реальный тип, затрудняет использование\n",[47,2004,2005,2007,2010,2012,2015,2017],{"class":49,"line":117},[47,2006,175],{"class":53},[47,2008,2009],{"class":57}," NewStorage",[47,2011,111],{"class":101},[47,2013,2014],{"class":57},"Storage",[47,2016,985],{"class":101},[47,2018,2019],{"class":162},"\u002F\u002F интерфейс\n",[47,2021,2022,2024,2026,2029],{"class":49,"line":123},[47,2023,204],{"class":53},[47,2025,689],{"class":53},[47,2027,2028],{"class":57},"RedisStorage",[47,2030,2031],{"class":101},"{}\n",[47,2033,2034],{"class":49,"line":128},[47,2035,120],{"class":101},[47,2037,2038],{"class":49,"line":141},[47,2039,65],{"emptyLinePlaceholder":64},[47,2041,2042],{"class":49,"line":149},[47,2043,2044],{"class":162},"\u002F\u002F Хорошо: возвращать конкретный тип\n",[47,2046,2047,2049,2051,2053,2055,2057],{"class":49,"line":154},[47,2048,175],{"class":53},[47,2050,2009],{"class":57},[47,2052,111],{"class":101},[47,2054,328],{"class":53},[47,2056,2028],{"class":57},[47,2058,102],{"class":101},[47,2060,2061,2063,2065,2067],{"class":49,"line":159},[47,2062,204],{"class":53},[47,2064,689],{"class":53},[47,2066,2028],{"class":57},[47,2068,2031],{"class":101},[47,2070,2071],{"class":49,"line":166},[47,2072,120],{"class":101},[16,2074,2075],{},"Исключение: когда возвращаемый интерфейс — часть публичного API и скрытие реализации принципиально (фабричный паттерн, моки).",[360,2077,2079],{"id":2078},"определяй-интерфейс-там-где-используешь","Определяй интерфейс там, где используешь",[16,2081,2082,2083,2086],{},"В Go интерфейс лучше определять на стороне ",[25,2084,2085],{},"потребителя",", а не производителя:",[38,2088,2090],{"className":40,"code":2089,"language":42,"meta":43,"style":43},"\u002F\u002F Пакет storage — экспортирует конкретный тип\npackage storage\n\ntype Postgres struct{}\nfunc (p *Postgres) GetUser(id int) (*User, error) { ... }\nfunc (p *Postgres) SaveUser(u *User) error { ... }\n\n\u002F\u002F Пакет service — определяет интерфейс под свои нужды\npackage service\n\n\u002F\u002F Нужен только GetUser — определяем минимальный интерфейс\ntype UserRepository interface {\n    GetUser(id int) (*User, error)\n}\n\ntype UserService struct {\n    repo UserRepository\n}\n",[20,2091,2092,2097,2104,2108,2119,2163,2200,2204,2209,2216,2220,2225,2236,2259,2263,2267,2278,2286],{"__ignoreMap":43},[47,2093,2094],{"class":49,"line":50},[47,2095,2096],{"class":162},"\u002F\u002F Пакет storage — экспортирует конкретный тип\n",[47,2098,2099,2101],{"class":49,"line":61},[47,2100,54],{"class":53},[47,2102,2103],{"class":57}," storage\n",[47,2105,2106],{"class":49,"line":68},[47,2107,65],{"emptyLinePlaceholder":64},[47,2109,2110,2112,2115,2117],{"class":49,"line":84},[47,2111,92],{"class":53},[47,2113,2114],{"class":57}," Postgres",[47,2116,136],{"class":53},[47,2118,2031],{"class":101},[47,2120,2121,2123,2125,2128,2130,2133,2135,2138,2140,2143,2145,2147,2149,2151,2153,2155,2158,2161],{"class":49,"line":89},[47,2122,175],{"class":53},[47,2124,178],{"class":101},[47,2126,2127],{"class":181},"p ",[47,2129,328],{"class":53},[47,2131,2132],{"class":57},"Postgres",[47,2134,188],{"class":101},[47,2136,2137],{"class":57},"GetUser",[47,2139,733],{"class":101},[47,2141,2142],{"class":181},"id",[47,2144,750],{"class":53},[47,2146,744],{"class":101},[47,2148,328],{"class":53},[47,2150,185],{"class":57},[47,2152,611],{"class":101},[47,2154,1007],{"class":53},[47,2156,2157],{"class":101},") { ",[47,2159,2160],{"class":53},"...",[47,2162,955],{"class":101},[47,2164,2165,2167,2169,2171,2173,2175,2177,2180,2182,2185,2188,2190,2192,2194,2196,2198],{"class":49,"line":105},[47,2166,175],{"class":53},[47,2168,178],{"class":101},[47,2170,2127],{"class":181},[47,2172,328],{"class":53},[47,2174,2132],{"class":57},[47,2176,188],{"class":101},[47,2178,2179],{"class":57},"SaveUser",[47,2181,733],{"class":101},[47,2183,2184],{"class":181},"u",[47,2186,2187],{"class":53}," *",[47,2189,185],{"class":57},[47,2191,188],{"class":101},[47,2193,1007],{"class":53},[47,2195,985],{"class":101},[47,2197,2160],{"class":53},[47,2199,955],{"class":101},[47,2201,2202],{"class":49,"line":117},[47,2203,65],{"emptyLinePlaceholder":64},[47,2205,2206],{"class":49,"line":123},[47,2207,2208],{"class":162},"\u002F\u002F Пакет service — определяет интерфейс под свои нужды\n",[47,2210,2211,2213],{"class":49,"line":128},[47,2212,54],{"class":53},[47,2214,2215],{"class":57}," service\n",[47,2217,2218],{"class":49,"line":141},[47,2219,65],{"emptyLinePlaceholder":64},[47,2221,2222],{"class":49,"line":149},[47,2223,2224],{"class":162},"\u002F\u002F Нужен только GetUser — определяем минимальный интерфейс\n",[47,2226,2227,2229,2232,2234],{"class":49,"line":154},[47,2228,92],{"class":53},[47,2230,2231],{"class":57}," UserRepository",[47,2233,98],{"class":53},[47,2235,102],{"class":101},[47,2237,2238,2241,2243,2245,2247,2249,2251,2253,2255,2257],{"class":49,"line":159},[47,2239,2240],{"class":57},"    GetUser",[47,2242,733],{"class":101},[47,2244,2142],{"class":181},[47,2246,750],{"class":53},[47,2248,744],{"class":101},[47,2250,328],{"class":53},[47,2252,185],{"class":57},[47,2254,611],{"class":101},[47,2256,1007],{"class":53},[47,2258,761],{"class":101},[47,2260,2261],{"class":49,"line":166},[47,2262,120],{"class":101},[47,2264,2265],{"class":49,"line":172},[47,2266,65],{"emptyLinePlaceholder":64},[47,2268,2269,2271,2274,2276],{"class":49,"line":201},[47,2270,92],{"class":53},[47,2272,2273],{"class":57}," UserService",[47,2275,136],{"class":53},[47,2277,102],{"class":101},[47,2279,2280,2283],{"class":49,"line":210},[47,2281,2282],{"class":101},"    repo ",[47,2284,2285],{"class":57},"UserRepository\n",[47,2287,2288],{"class":49,"line":215},[47,2289,120],{"class":101},[16,2291,2292],{},"Это делает зависимости явными, а тестирование — тривиальным: достаточно написать mock с одним методом.",[360,2294,2296],{"id":2295},"интерфейсы-для-тестирования","Интерфейсы для тестирования",[38,2298,2300],{"className":40,"code":2299,"language":42,"meta":43,"style":43},"\u002F\u002F Продакшн-код зависит от интерфейса\ntype Mailer interface {\n    Send(to, subject, body string) error\n}\n\ntype OrderService struct {\n    mailer Mailer\n}\n\n\u002F\u002F Мок для тестов — реализует тот же интерфейс\ntype MockMailer struct {\n    Sent []string\n}\n\nfunc (m *MockMailer) Send(to, subject, body string) error {\n    m.Sent = append(m.Sent, to)\n    return nil\n}\n\nfunc TestOrderService(t *testing.T) {\n    mock := &MockMailer{}\n    svc := OrderService{mailer: mock}\n    svc.PlaceOrder(...)\n    assert.Contains(t, mock.Sent, \"customer@example.com\")\n}\n",[20,2301,2302,2307,2318,2345,2349,2353,2364,2372,2376,2380,2385,2396,2403,2407,2411,2450,2463,2470,2474,2478,2502,2515,2527,2542,2559],{"__ignoreMap":43},[47,2303,2304],{"class":49,"line":50},[47,2305,2306],{"class":162},"\u002F\u002F Продакшн-код зависит от интерфейса\n",[47,2308,2309,2311,2314,2316],{"class":49,"line":61},[47,2310,92],{"class":53},[47,2312,2313],{"class":57}," Mailer",[47,2315,98],{"class":53},[47,2317,102],{"class":101},[47,2319,2320,2323,2325,2328,2330,2333,2335,2338,2340,2342],{"class":49,"line":68},[47,2321,2322],{"class":57},"    Send",[47,2324,733],{"class":101},[47,2326,2327],{"class":181},"to",[47,2329,611],{"class":101},[47,2331,2332],{"class":181},"subject",[47,2334,611],{"class":101},[47,2336,2337],{"class":181},"body",[47,2339,1161],{"class":53},[47,2341,188],{"class":101},[47,2343,2344],{"class":53},"error\n",[47,2346,2347],{"class":49,"line":84},[47,2348,120],{"class":101},[47,2350,2351],{"class":49,"line":89},[47,2352,65],{"emptyLinePlaceholder":64},[47,2354,2355,2357,2360,2362],{"class":49,"line":105},[47,2356,92],{"class":53},[47,2358,2359],{"class":57}," OrderService",[47,2361,136],{"class":53},[47,2363,102],{"class":101},[47,2365,2366,2369],{"class":49,"line":117},[47,2367,2368],{"class":101},"    mailer ",[47,2370,2371],{"class":57},"Mailer\n",[47,2373,2374],{"class":49,"line":123},[47,2375,120],{"class":101},[47,2377,2378],{"class":49,"line":128},[47,2379,65],{"emptyLinePlaceholder":64},[47,2381,2382],{"class":49,"line":141},[47,2383,2384],{"class":162},"\u002F\u002F Мок для тестов — реализует тот же интерфейс\n",[47,2386,2387,2389,2392,2394],{"class":49,"line":149},[47,2388,92],{"class":53},[47,2390,2391],{"class":57}," MockMailer",[47,2393,136],{"class":53},[47,2395,102],{"class":101},[47,2397,2398,2401],{"class":49,"line":154},[47,2399,2400],{"class":101},"    Sent []",[47,2402,114],{"class":53},[47,2404,2405],{"class":49,"line":159},[47,2406,120],{"class":101},[47,2408,2409],{"class":49,"line":166},[47,2410,65],{"emptyLinePlaceholder":64},[47,2412,2413,2415,2417,2420,2422,2425,2427,2430,2432,2434,2436,2438,2440,2442,2444,2446,2448],{"class":49,"line":172},[47,2414,175],{"class":53},[47,2416,178],{"class":101},[47,2418,2419],{"class":181},"m ",[47,2421,328],{"class":53},[47,2423,2424],{"class":57},"MockMailer",[47,2426,188],{"class":101},[47,2428,2429],{"class":57},"Send",[47,2431,733],{"class":101},[47,2433,2327],{"class":181},[47,2435,611],{"class":101},[47,2437,2332],{"class":181},[47,2439,611],{"class":101},[47,2441,2337],{"class":181},[47,2443,1161],{"class":53},[47,2445,188],{"class":101},[47,2447,1007],{"class":53},[47,2449,102],{"class":101},[47,2451,2452,2455,2457,2460],{"class":49,"line":201},[47,2453,2454],{"class":101},"    m.Sent ",[47,2456,663],{"class":53},[47,2458,2459],{"class":57}," append",[47,2461,2462],{"class":101},"(m.Sent, to)\n",[47,2464,2465,2467],{"class":49,"line":210},[47,2466,204],{"class":53},[47,2468,2469],{"class":336}," nil\n",[47,2471,2472],{"class":49,"line":215},[47,2473,120],{"class":101},[47,2475,2476],{"class":49,"line":220},[47,2477,65],{"emptyLinePlaceholder":64},[47,2479,2480,2482,2485,2487,2490,2492,2495,2497,2500],{"class":49,"line":231},[47,2481,175],{"class":53},[47,2483,2484],{"class":57}," TestOrderService",[47,2486,733],{"class":101},[47,2488,2489],{"class":181},"t",[47,2491,2187],{"class":53},[47,2493,2494],{"class":57},"testing",[47,2496,411],{"class":101},[47,2498,2499],{"class":57},"T",[47,2501,1530],{"class":101},[47,2503,2504,2507,2509,2511,2513],{"class":49,"line":260},[47,2505,2506],{"class":101},"    mock ",[47,2508,1062],{"class":53},[47,2510,689],{"class":53},[47,2512,2424],{"class":57},[47,2514,2031],{"class":101},[47,2516,2517,2520,2522,2524],{"class":49,"line":280},[47,2518,2519],{"class":101},"    svc ",[47,2521,1062],{"class":53},[47,2523,2359],{"class":57},[47,2525,2526],{"class":101},"{mailer: mock}\n",[47,2528,2530,2533,2536,2538,2540],{"class":49,"line":2529},23,[47,2531,2532],{"class":101},"    svc.",[47,2534,2535],{"class":57},"PlaceOrder",[47,2537,733],{"class":101},[47,2539,2160],{"class":53},[47,2541,761],{"class":101},[47,2543,2545,2548,2551,2554,2557],{"class":49,"line":2544},24,[47,2546,2547],{"class":101},"    assert.",[47,2549,2550],{"class":57},"Contains",[47,2552,2553],{"class":101},"(t, mock.Sent, ",[47,2555,2556],{"class":74},"\"customer@example.com\"",[47,2558,761],{"class":101},[47,2560,2562],{"class":49,"line":2561},25,[47,2563,120],{"class":101},[30,2565],{},[33,2567,2569],{"id":2568},"вопросы-на-собеседовании","Вопросы на собеседовании",[16,2571,2572,2575,2578,2579,2581],{},[25,2573,2574],{},"Q: Как Go определяет, что тип реализует интерфейс?",[2576,2577],"br",{},"\nA: Structural typing — компилятор проверяет наличие всех методов интерфейса с совпадающими сигнатурами. Явного объявления (",[20,2580,22],{},") не нужно. Проверка происходит в момент присвоения значения переменной интерфейсного типа.",[16,2583,2584,2587,2589,2590,2592,2593,2595,2596,879,2598,2600,2601,2603],{},[25,2585,2586],{},"Q: Из чего состоит интерфейсная переменная внутри?",[2576,2588],{},"\nA: Из двух машинных слов. Для непустого интерфейса — ",[20,2591,559],{},": указатель на ",[20,2594,463],{}," (тип + таблица методов) и указатель на данные. Для пустого ",[20,2597,366],{},[20,2599,370],{}," — ",[20,2602,426],{},": указатель на тип и указатель на данные, без таблицы методов.",[16,2605,2606,2615,2617,2618,2620,2621,2623,2624,2626],{},[25,2607,2608,2609,2611,2612,2614],{},"Q: Чем ",[20,2610,559],{}," отличается от ",[20,2613,426],{},"?",[2576,2616],{},"\nA: ",[20,2619,426],{}," используется для пустого интерфейса — хранит только тип и данные, таблицы методов нет. ",[20,2622,559],{}," — для непустых интерфейсов — вместо голого типа хранит ",[20,2625,463],{},": структуру с типом и таблицей указателей на методы для диспетчеризации вызовов.",[16,2628,2629,2632,2634,2635,2638,2639,2641],{},[25,2630,2631],{},"Q: Когда интерфейс равен nil?",[2576,2633],{},"\nA: Только когда оба поля — тип и данные — равны nil. Если тип задан, а данные nil (typed nil pointer, упакованный в интерфейс) — интерфейс не nil. Это главная ловушка: ",[20,2636,2637],{},"var p *MyError = nil; return p"," при возврате через ",[20,2640,1007],{}," даст ненулевой интерфейс.",[16,2643,2644,2647,2649,2650,2653,2654,2657,2658,2661],{},[25,2645,2646],{},"Q: Что безопаснее — одноаргументный или двухаргументный type assertion?",[2576,2648],{},"\nA: Двухаргументный: ",[20,2651,2652],{},"v, ok := i.(Type)",". Одноаргументный ",[20,2655,2656],{},"v := i.(Type)"," паникует, если тип не совпал. В продакшн-коде почти всегда нужна форма с ",[20,2659,2660],{},"ok",", кроме случаев, когда несоответствие типа — программная ошибка, а не ожидаемая ситуация.",[16,2663,2664,2667,2669,2670,2672,2673,2675],{},[25,2665,2666],{},"Q: В чём разница между type assertion и type switch?",[2576,2668],{},"\nA: Type assertion проверяет один конкретный тип: ",[20,2671,2652],{},". Type switch обрабатывает несколько вариантов последовательно, и в каждой ветке ",[20,2674,1711],{}," имеет конкретный тип — компилятор это знает. Type switch предпочтительнее цепочки assertion'ов.",[16,2677,2678,2681,2683,2684,2686,2687,2689],{},[25,2679,2680],{},"Q: Почему вызов метода через интерфейс медленнее прямого вызова?",[2576,2682],{},"\nA: Dynamic dispatch: в рантайме нужно загрузить ",[20,2685,463],{},", найти адрес метода в таблице ",[20,2688,582],{},", потом вызвать. Прямой вызов известен на этапе компиляции и может быть заинлайнен. Разница — единицы наносекунд, критично только в очень горячих путях.",[16,2691,2692,2695,2697],{},[25,2693,2694],{},"Q: Что означает принцип \"accept interfaces, return structs\"?",[2576,2696],{},"\nA: Функции принимают интерфейсы — это даёт гибкость: любой тип с нужными методами подходит. Возвращают конкретные типы — это даёт ясность: вызывающий видит реальную структуру и имеет доступ ко всем её методам, а не только к тем, что объявлены в интерфейсе.",[16,2699,2700,2703,2705],{},[25,2701,2702],{},"Q: Где лучше определять интерфейс — в пакете производителя или потребителя?",[2576,2704],{},"\nA: На стороне потребителя. Это позволяет определить минимальный интерфейс под конкретные нужды, не завися от того, что экспортирует производитель. Производитель возвращает конкретный тип, а потребитель сам решает, какую абстракцию ему нужна.",[16,2707,2708,2711,2617,2713,2716,2717,2719,2720,2723,2724,2727],{},[25,2709,2710],{},"Q: Как во время компиляции проверить, что тип реализует интерфейс?",[2576,2712],{},[20,2714,2715],{},"var _ MyInterface = (*MyType)(nil)"," — присвоение nil-указателя нужного типа переменной интерфейсного типа. Если ",[20,2718,1873],{}," не реализует ",[20,2721,2722],{},"MyInterface"," — ошибка компиляции. ",[20,2725,2726],{},"_"," означает, что переменная нам не нужна, это чисто compile-time проверка.",[30,2729],{},[11,2731,2733],{"id":2732},"задачи-интерфейс","Задачи: Интерфейс",[30,2735],{},[16,2737,2738],{},[25,2739,2740],{},"Задача 1: Реализация интерфейса",[16,2742,2743,2746],{},[25,2744,2745],{},"Уровень:"," Лёгкая",[16,2748,2749,2752],{},[25,2750,2751],{},"Что проверяет:"," базовое понимание интерфейсов и duck typing",[16,2754,2755,2758,2759,2762,2763,896,2766,2769,2770,2772,2773,2776],{},[25,2756,2757],{},"Условие:"," Дан интерфейс ",[20,2760,2761],{},"Shape",". Реализуй два типа ",[20,2764,2765],{},"Circle",[20,2767,2768],{},"Rectangle",", каждый реализует ",[20,2771,2761],{},". Напиши функцию ",[20,2774,2775],{},"totalArea(shapes []Shape) float64"," которая возвращает суммарную площадь.",[38,2778,2780],{"className":40,"code":2779,"language":42,"meta":43,"style":43},"type Shape interface {\n    Area() float64\n    Perimeter() float64\n}\n",[20,2781,2782,2793,2803,2812],{"__ignoreMap":43},[47,2783,2784,2786,2789,2791],{"class":49,"line":50},[47,2785,92],{"class":53},[47,2787,2788],{"class":57}," Shape",[47,2790,98],{"class":53},[47,2792,102],{"class":101},[47,2794,2795,2798,2800],{"class":49,"line":61},[47,2796,2797],{"class":57},"    Area",[47,2799,111],{"class":101},[47,2801,2802],{"class":53},"float64\n",[47,2804,2805,2808,2810],{"class":49,"line":68},[47,2806,2807],{"class":57},"    Perimeter",[47,2809,111],{"class":101},[47,2811,2802],{"class":53},[47,2813,2814],{"class":49,"line":84},[47,2815,120],{"class":101},[16,2817,2818],{},[25,2819,2820],{},"Примеры:",[38,2822,2827],{"className":2823,"code":2825,"language":2826},[2824],"language-text","Circle{Radius: 5}       → Area ≈ 78.54, Perimeter ≈ 31.42\nRectangle{Width: 4, Height: 6} → Area = 24, Perimeter = 20\ntotalArea([]Shape{Circle{5}, Rectangle{4, 6}}) ≈ 102.54\n","text",[20,2828,2825],{"__ignoreMap":43},[16,2830,2831],{},[25,2832,2833],{},"Решение:",[38,2835,2837],{"className":40,"code":2836,"language":42,"meta":43,"style":43},"package main\n\nimport (\n    \"fmt\"\n    \"math\"\n)\n\ntype Shape interface {\n    Area() float64\n    Perimeter() float64\n}\n\ntype Circle struct{ Radius float64 }\ntype Rectangle struct{ Width, Height float64 }\n\nfunc (c Circle) Area() float64      { return math.Pi * c.Radius * c.Radius }\nfunc (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius }\n\nfunc (r Rectangle) Area() float64      { return r.Width * r.Height }\nfunc (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) }\n\nfunc totalArea(shapes []Shape) float64 {\n    total := 0.0\n    for _, s := range shapes {\n        total += s.Area()\n    }\n    return total\n}\n\nfunc main() {\n    shapes := []Shape{Circle{Radius: 5}, Rectangle{Width: 4, Height: 6}}\n    fmt.Printf(\"%.2f\\n\", totalArea(shapes)) \u002F\u002F 102.54\n}\n",[20,2838,2839,2845,2849,2856,2865,2874,2878,2882,2892,2900,2908,2912,2916,2933,2949,2953,2991,3025,3029,3060,3095,3099,3121,3130,3144,3157,3162,3169,3174,3179,3188,3230,3258],{"__ignoreMap":43},[47,2840,2841,2843],{"class":49,"line":50},[47,2842,54],{"class":53},[47,2844,58],{"class":57},[47,2846,2847],{"class":49,"line":61},[47,2848,65],{"emptyLinePlaceholder":64},[47,2850,2851,2853],{"class":49,"line":68},[47,2852,71],{"class":53},[47,2854,2855],{"class":101}," (\n",[47,2857,2858,2861,2863],{"class":49,"line":84},[47,2859,2860],{"class":74},"    \"",[47,2862,78],{"class":57},[47,2864,81],{"class":74},[47,2866,2867,2869,2872],{"class":49,"line":89},[47,2868,2860],{"class":74},[47,2870,2871],{"class":57},"math",[47,2873,81],{"class":74},[47,2875,2876],{"class":49,"line":105},[47,2877,761],{"class":101},[47,2879,2880],{"class":49,"line":117},[47,2881,65],{"emptyLinePlaceholder":64},[47,2883,2884,2886,2888,2890],{"class":49,"line":123},[47,2885,92],{"class":53},[47,2887,2788],{"class":57},[47,2889,98],{"class":53},[47,2891,102],{"class":101},[47,2893,2894,2896,2898],{"class":49,"line":128},[47,2895,2797],{"class":57},[47,2897,111],{"class":101},[47,2899,2802],{"class":53},[47,2901,2902,2904,2906],{"class":49,"line":141},[47,2903,2807],{"class":57},[47,2905,111],{"class":101},[47,2907,2802],{"class":53},[47,2909,2910],{"class":49,"line":149},[47,2911,120],{"class":101},[47,2913,2914],{"class":49,"line":154},[47,2915,65],{"emptyLinePlaceholder":64},[47,2917,2918,2920,2923,2925,2928,2931],{"class":49,"line":159},[47,2919,92],{"class":53},[47,2921,2922],{"class":57}," Circle",[47,2924,136],{"class":53},[47,2926,2927],{"class":101},"{ Radius ",[47,2929,2930],{"class":53},"float64",[47,2932,955],{"class":101},[47,2934,2935,2937,2940,2942,2945,2947],{"class":49,"line":166},[47,2936,92],{"class":53},[47,2938,2939],{"class":57}," Rectangle",[47,2941,136],{"class":53},[47,2943,2944],{"class":101},"{ Width, Height ",[47,2946,2930],{"class":53},[47,2948,955],{"class":101},[47,2950,2951],{"class":49,"line":172},[47,2952,65],{"emptyLinePlaceholder":64},[47,2954,2955,2957,2959,2962,2964,2966,2969,2971,2973,2976,2978,2981,2983,2986,2988],{"class":49,"line":201},[47,2956,175],{"class":53},[47,2958,178],{"class":101},[47,2960,2961],{"class":181},"c ",[47,2963,2765],{"class":57},[47,2965,188],{"class":101},[47,2967,2968],{"class":57},"Area",[47,2970,111],{"class":101},[47,2972,2930],{"class":53},[47,2974,2975],{"class":101},"      { ",[47,2977,988],{"class":53},[47,2979,2980],{"class":101}," math.Pi ",[47,2982,328],{"class":53},[47,2984,2985],{"class":101}," c.Radius ",[47,2987,328],{"class":53},[47,2989,2990],{"class":101}," c.Radius }\n",[47,2992,2993,2995,2997,2999,3001,3003,3006,3008,3010,3012,3014,3017,3019,3021,3023],{"class":49,"line":210},[47,2994,175],{"class":53},[47,2996,178],{"class":101},[47,2998,2961],{"class":181},[47,3000,2765],{"class":57},[47,3002,188],{"class":101},[47,3004,3005],{"class":57},"Perimeter",[47,3007,111],{"class":101},[47,3009,2930],{"class":53},[47,3011,985],{"class":101},[47,3013,988],{"class":53},[47,3015,3016],{"class":336}," 2",[47,3018,2187],{"class":53},[47,3020,2980],{"class":101},[47,3022,328],{"class":53},[47,3024,2990],{"class":101},[47,3026,3027],{"class":49,"line":215},[47,3028,65],{"emptyLinePlaceholder":64},[47,3030,3031,3033,3035,3038,3040,3042,3044,3046,3048,3050,3052,3055,3057],{"class":49,"line":220},[47,3032,175],{"class":53},[47,3034,178],{"class":101},[47,3036,3037],{"class":181},"r ",[47,3039,2768],{"class":57},[47,3041,188],{"class":101},[47,3043,2968],{"class":57},[47,3045,111],{"class":101},[47,3047,2930],{"class":53},[47,3049,2975],{"class":101},[47,3051,988],{"class":53},[47,3053,3054],{"class":101}," r.Width ",[47,3056,328],{"class":53},[47,3058,3059],{"class":101}," r.Height }\n",[47,3061,3062,3064,3066,3068,3070,3072,3074,3076,3078,3080,3082,3084,3086,3089,3092],{"class":49,"line":231},[47,3063,175],{"class":53},[47,3065,178],{"class":101},[47,3067,3037],{"class":181},[47,3069,2768],{"class":57},[47,3071,188],{"class":101},[47,3073,3005],{"class":57},[47,3075,111],{"class":101},[47,3077,2930],{"class":53},[47,3079,985],{"class":101},[47,3081,988],{"class":53},[47,3083,3016],{"class":336},[47,3085,2187],{"class":53},[47,3087,3088],{"class":101}," (r.Width ",[47,3090,3091],{"class":53},"+",[47,3093,3094],{"class":101}," r.Height) }\n",[47,3096,3097],{"class":49,"line":260},[47,3098,65],{"emptyLinePlaceholder":64},[47,3100,3101,3103,3106,3108,3111,3113,3115,3117,3119],{"class":49,"line":280},[47,3102,175],{"class":53},[47,3104,3105],{"class":57}," totalArea",[47,3107,733],{"class":101},[47,3109,3110],{"class":181},"shapes",[47,3112,738],{"class":101},[47,3114,2761],{"class":57},[47,3116,188],{"class":101},[47,3118,2930],{"class":53},[47,3120,102],{"class":101},[47,3122,3123,3125,3127],{"class":49,"line":2529},[47,3124,1793],{"class":101},[47,3126,1062],{"class":53},[47,3128,3129],{"class":336}," 0.0\n",[47,3131,3132,3134,3137,3139,3141],{"class":49,"line":2544},[47,3133,1803],{"class":53},[47,3135,3136],{"class":101}," _, s ",[47,3138,1062],{"class":53},[47,3140,1811],{"class":53},[47,3142,3143],{"class":101}," shapes {\n",[47,3145,3146,3148,3150,3153,3155],{"class":49,"line":2561},[47,3147,1819],{"class":101},[47,3149,1822],{"class":53},[47,3151,3152],{"class":101}," s.",[47,3154,2968],{"class":57},[47,3156,1067],{"class":101},[47,3158,3160],{"class":49,"line":3159},26,[47,3161,1218],{"class":101},[47,3163,3165,3167],{"class":49,"line":3164},27,[47,3166,204],{"class":53},[47,3168,1844],{"class":101},[47,3170,3172],{"class":49,"line":3171},28,[47,3173,120],{"class":101},[47,3175,3177],{"class":49,"line":3176},29,[47,3178,65],{"emptyLinePlaceholder":64},[47,3180,3182,3184,3186],{"class":49,"line":3181},30,[47,3183,175],{"class":53},[47,3185,225],{"class":57},[47,3187,228],{"class":101},[47,3189,3191,3194,3196,3198,3200,3202,3204,3207,3210,3213,3215,3218,3221,3224,3227],{"class":49,"line":3190},31,[47,3192,3193],{"class":101},"    shapes ",[47,3195,1062],{"class":53},[47,3197,738],{"class":101},[47,3199,2761],{"class":57},[47,3201,1208],{"class":101},[47,3203,2765],{"class":57},[47,3205,3206],{"class":101},"{Radius: ",[47,3208,3209],{"class":336},"5",[47,3211,3212],{"class":101},"}, ",[47,3214,2768],{"class":57},[47,3216,3217],{"class":101},"{Width: ",[47,3219,3220],{"class":336},"4",[47,3222,3223],{"class":101},", Height: ",[47,3225,3226],{"class":336},"6",[47,3228,3229],{"class":101},"}}\n",[47,3231,3233,3235,3238,3240,3242,3245,3247,3249,3252,3255],{"class":49,"line":3232},32,[47,3234,263],{"class":101},[47,3236,3237],{"class":57},"Printf",[47,3239,733],{"class":101},[47,3241,1561],{"class":74},[47,3243,3244],{"class":336},"%.2f\\n",[47,3246,1561],{"class":74},[47,3248,611],{"class":101},[47,3250,3251],{"class":57},"totalArea",[47,3253,3254],{"class":101},"(shapes)) ",[47,3256,3257],{"class":162},"\u002F\u002F 102.54\n",[47,3259,3261],{"class":49,"line":3260},33,[47,3262,120],{"class":101},[30,3264],{},[16,3266,3267],{},[25,3268,3269],{},"Задача 2: Ловушка nil interface",[16,3271,3272,3274],{},[25,3273,2745],{}," Средняя",[16,3276,3277,3279],{},[25,3278,2751],{}," понимание iface, typed nil, главная ловушка интерфейсов",[16,3281,3282,3284],{},[25,3283,2757],{}," Что выведет код? Объясни каждый результат.",[38,3286,3288],{"className":40,"code":3287,"language":42,"meta":43,"style":43},"package main\n\nimport \"fmt\"\n\ntype MyError struct{ msg string }\n\nfunc (e *MyError) Error() string { return e.msg }\n\nfunc getError(fail bool) error {\n    var err *MyError\n    if fail {\n        err = &MyError{\"something went wrong\"}\n    }\n    return err\n}\n\nfunc getErrorFixed(fail bool) error {\n    if fail {\n        return &MyError{\"something went wrong\"}\n    }\n    return nil\n}\n\nfunc main() {\n    err1 := getError(false)\n    err2 := getError(true)\n    err3 := getErrorFixed(false)\n\n    fmt.Println(err1 == nil)\n    fmt.Println(err2 == nil)\n    fmt.Println(err3 == nil)\n    fmt.Println(err1)\n}\n",[20,3289,3290,3296,3300,3310,3314,3328,3332,3358,3362,3381,3392,3399,3416,3420,3427,3431,3435,3454,3460,3474,3478,3484,3488,3492,3500,3516,3532,3547,3551,3566,3581,3596,3605],{"__ignoreMap":43},[47,3291,3292,3294],{"class":49,"line":50},[47,3293,54],{"class":53},[47,3295,58],{"class":57},[47,3297,3298],{"class":49,"line":61},[47,3299,65],{"emptyLinePlaceholder":64},[47,3301,3302,3304,3306,3308],{"class":49,"line":68},[47,3303,71],{"class":53},[47,3305,75],{"class":74},[47,3307,78],{"class":57},[47,3309,81],{"class":74},[47,3311,3312],{"class":49,"line":84},[47,3313,65],{"emptyLinePlaceholder":64},[47,3315,3316,3318,3320,3322,3324,3326],{"class":49,"line":89},[47,3317,92],{"class":53},[47,3319,945],{"class":57},[47,3321,136],{"class":53},[47,3323,950],{"class":101},[47,3325,196],{"class":53},[47,3327,955],{"class":101},[47,3329,3330],{"class":49,"line":105},[47,3331,65],{"emptyLinePlaceholder":64},[47,3333,3334,3336,3338,3340,3342,3344,3346,3348,3350,3352,3354,3356],{"class":49,"line":117},[47,3335,175],{"class":53},[47,3337,178],{"class":101},[47,3339,968],{"class":181},[47,3341,328],{"class":53},[47,3343,973],{"class":57},[47,3345,188],{"class":101},[47,3347,978],{"class":57},[47,3349,111],{"class":101},[47,3351,196],{"class":53},[47,3353,985],{"class":101},[47,3355,988],{"class":53},[47,3357,991],{"class":101},[47,3359,3360],{"class":49,"line":123},[47,3361,65],{"emptyLinePlaceholder":64},[47,3363,3364,3366,3368,3370,3373,3375,3377,3379],{"class":49,"line":128},[47,3365,175],{"class":53},[47,3367,1002],{"class":57},[47,3369,733],{"class":101},[47,3371,3372],{"class":181},"fail",[47,3374,1599],{"class":53},[47,3376,188],{"class":101},[47,3378,1007],{"class":53},[47,3380,102],{"class":101},[47,3382,3383,3385,3387,3389],{"class":49,"line":141},[47,3384,234],{"class":53},[47,3386,1174],{"class":101},[47,3388,328],{"class":53},[47,3390,3391],{"class":57},"MyError\n",[47,3393,3394,3396],{"class":49,"line":149},[47,3395,1184],{"class":53},[47,3397,3398],{"class":101}," fail {\n",[47,3400,3401,3403,3405,3407,3409,3411,3414],{"class":49,"line":154},[47,3402,1198],{"class":101},[47,3404,663],{"class":53},[47,3406,689],{"class":53},[47,3408,973],{"class":57},[47,3410,1208],{"class":101},[47,3412,3413],{"class":74},"\"something went wrong\"",[47,3415,120],{"class":101},[47,3417,3418],{"class":49,"line":159},[47,3419,1218],{"class":101},[47,3421,3422,3424],{"class":49,"line":166},[47,3423,204],{"class":53},[47,3425,3426],{"class":101}," err\n",[47,3428,3429],{"class":49,"line":172},[47,3430,120],{"class":101},[47,3432,3433],{"class":49,"line":201},[47,3434,65],{"emptyLinePlaceholder":64},[47,3436,3437,3439,3442,3444,3446,3448,3450,3452],{"class":49,"line":210},[47,3438,175],{"class":53},[47,3440,3441],{"class":57}," getErrorFixed",[47,3443,733],{"class":101},[47,3445,3372],{"class":181},[47,3447,1599],{"class":53},[47,3449,188],{"class":101},[47,3451,1007],{"class":53},[47,3453,102],{"class":101},[47,3455,3456,3458],{"class":49,"line":215},[47,3457,1184],{"class":53},[47,3459,3398],{"class":101},[47,3461,3462,3464,3466,3468,3470,3472],{"class":49,"line":220},[47,3463,1275],{"class":53},[47,3465,689],{"class":53},[47,3467,973],{"class":57},[47,3469,1208],{"class":101},[47,3471,3413],{"class":74},[47,3473,120],{"class":101},[47,3475,3476],{"class":49,"line":231},[47,3477,1218],{"class":101},[47,3479,3480,3482],{"class":49,"line":260},[47,3481,204],{"class":53},[47,3483,2469],{"class":336},[47,3485,3486],{"class":49,"line":280},[47,3487,120],{"class":101},[47,3489,3490],{"class":49,"line":2529},[47,3491,65],{"emptyLinePlaceholder":64},[47,3493,3494,3496,3498],{"class":49,"line":2544},[47,3495,175],{"class":53},[47,3497,225],{"class":57},[47,3499,228],{"class":101},[47,3501,3502,3505,3507,3509,3511,3514],{"class":49,"line":2561},[47,3503,3504],{"class":101},"    err1 ",[47,3506,1062],{"class":53},[47,3508,1002],{"class":57},[47,3510,733],{"class":101},[47,3512,3513],{"class":336},"false",[47,3515,761],{"class":101},[47,3517,3518,3521,3523,3525,3527,3530],{"class":49,"line":3159},[47,3519,3520],{"class":101},"    err2 ",[47,3522,1062],{"class":53},[47,3524,1002],{"class":57},[47,3526,733],{"class":101},[47,3528,3529],{"class":336},"true",[47,3531,761],{"class":101},[47,3533,3534,3537,3539,3541,3543,3545],{"class":49,"line":3164},[47,3535,3536],{"class":101},"    err3 ",[47,3538,1062],{"class":53},[47,3540,3441],{"class":57},[47,3542,733],{"class":101},[47,3544,3513],{"class":336},[47,3546,761],{"class":101},[47,3548,3549],{"class":49,"line":3171},[47,3550,65],{"emptyLinePlaceholder":64},[47,3552,3553,3555,3557,3560,3562,3564],{"class":49,"line":3176},[47,3554,263],{"class":101},[47,3556,266],{"class":57},[47,3558,3559],{"class":101},"(err1 ",[47,3561,1079],{"class":53},[47,3563,1025],{"class":336},[47,3565,761],{"class":101},[47,3567,3568,3570,3572,3575,3577,3579],{"class":49,"line":3181},[47,3569,263],{"class":101},[47,3571,266],{"class":57},[47,3573,3574],{"class":101},"(err2 ",[47,3576,1079],{"class":53},[47,3578,1025],{"class":336},[47,3580,761],{"class":101},[47,3582,3583,3585,3587,3590,3592,3594],{"class":49,"line":3190},[47,3584,263],{"class":101},[47,3586,266],{"class":57},[47,3588,3589],{"class":101},"(err3 ",[47,3591,1079],{"class":53},[47,3593,1025],{"class":336},[47,3595,761],{"class":101},[47,3597,3598,3600,3602],{"class":49,"line":3232},[47,3599,263],{"class":101},[47,3601,266],{"class":57},[47,3603,3604],{"class":101},"(err1)\n",[47,3606,3607],{"class":49,"line":3260},[47,3608,120],{"class":101},[16,3610,3611],{},[25,3612,3613],{},"Ожидаемый ответ:",[38,3615,3618],{"className":3616,"code":3617,"language":2826},[2824],"false\nfalse\ntrue\n\u003Cnil>\n",[20,3619,3617],{"__ignoreMap":43},[16,3621,3622],{},[25,3623,2833],{},[38,3625,3627],{"className":40,"code":3626,"language":42,"meta":43,"style":43},"\u002F\u002F err1: getError(false) возвращает var err *MyError = nil.\n\u002F\u002F При возврате через interface error создаётся iface:\n\u002F\u002F tab=*MyError, data=nil.\n\u002F\u002F Интерфейс НЕ nil — тип задан.\n\u002F\u002F err1 == nil → false. Печатает \u003Cnil> потому что данные nil.\n\n\u002F\u002F err2: аналогично, но data указывает на MyError.\n\u002F\u002F err2 == nil → false.\n\n\u002F\u002F err3: getErrorFixed возвращает nil напрямую —\n\u002F\u002F оба поля iface (tab и data) равны nil.\n\u002F\u002F err3 == nil → true.\n\n\u002F\u002F Вывод: никогда не возвращай typed nil через интерфейс.\n\u002F\u002F Всегда возвращай nil напрямую.\n",[20,3628,3629,3634,3639,3644,3649,3654,3658,3663,3668,3672,3677,3682,3687,3691,3696],{"__ignoreMap":43},[47,3630,3631],{"class":49,"line":50},[47,3632,3633],{"class":162},"\u002F\u002F err1: getError(false) возвращает var err *MyError = nil.\n",[47,3635,3636],{"class":49,"line":61},[47,3637,3638],{"class":162},"\u002F\u002F При возврате через interface error создаётся iface:\n",[47,3640,3641],{"class":49,"line":68},[47,3642,3643],{"class":162},"\u002F\u002F tab=*MyError, data=nil.\n",[47,3645,3646],{"class":49,"line":84},[47,3647,3648],{"class":162},"\u002F\u002F Интерфейс НЕ nil — тип задан.\n",[47,3650,3651],{"class":49,"line":89},[47,3652,3653],{"class":162},"\u002F\u002F err1 == nil → false. Печатает \u003Cnil> потому что данные nil.\n",[47,3655,3656],{"class":49,"line":105},[47,3657,65],{"emptyLinePlaceholder":64},[47,3659,3660],{"class":49,"line":117},[47,3661,3662],{"class":162},"\u002F\u002F err2: аналогично, но data указывает на MyError.\n",[47,3664,3665],{"class":49,"line":123},[47,3666,3667],{"class":162},"\u002F\u002F err2 == nil → false.\n",[47,3669,3670],{"class":49,"line":128},[47,3671,65],{"emptyLinePlaceholder":64},[47,3673,3674],{"class":49,"line":141},[47,3675,3676],{"class":162},"\u002F\u002F err3: getErrorFixed возвращает nil напрямую —\n",[47,3678,3679],{"class":49,"line":149},[47,3680,3681],{"class":162},"\u002F\u002F оба поля iface (tab и data) равны nil.\n",[47,3683,3684],{"class":49,"line":154},[47,3685,3686],{"class":162},"\u002F\u002F err3 == nil → true.\n",[47,3688,3689],{"class":49,"line":159},[47,3690,65],{"emptyLinePlaceholder":64},[47,3692,3693],{"class":49,"line":166},[47,3694,3695],{"class":162},"\u002F\u002F Вывод: никогда не возвращай typed nil через интерфейс.\n",[47,3697,3698],{"class":49,"line":172},[47,3699,3700],{"class":162},"\u002F\u002F Всегда возвращай nil напрямую.\n",[30,3702],{},[16,3704,3705],{},[25,3706,3707],{},"Задача 3: Цепочка middleware через интерфейс",[16,3709,3710,3712],{},[25,3711,2745],{}," Сложная",[16,3714,3715,3717],{},[25,3716,2751],{}," практическое применение интерфейсов, паттерн декоратор",[16,3719,3720,3722,3723,3726,3727,3730,3731,3734,3735,3738],{},[25,3721,2757],{}," Реализуй систему middleware для обработки сообщений. Есть интерфейс ",[20,3724,3725],{},"Processor",". Реализуй три обёртки: ",[20,3728,3729],{},"LoggingProcessor"," (логирует сообщение до и после), ",[20,3732,3733],{},"UpperCaseProcessor"," (переводит в верхний регистр) и ",[20,3736,3737],{},"TrimProcessor"," (убирает пробелы). Обёртки должны комбинироваться в цепочку.",[38,3740,3742],{"className":40,"code":3741,"language":42,"meta":43,"style":43},"type Processor interface {\n    Process(msg string) string\n}\n",[20,3743,3744,3755,3771],{"__ignoreMap":43},[47,3745,3746,3748,3751,3753],{"class":49,"line":50},[47,3747,92],{"class":53},[47,3749,3750],{"class":57}," Processor",[47,3752,98],{"class":53},[47,3754,102],{"class":101},[47,3756,3757,3760,3762,3765,3767,3769],{"class":49,"line":61},[47,3758,3759],{"class":57},"    Process",[47,3761,733],{"class":101},[47,3763,3764],{"class":181},"msg",[47,3766,1161],{"class":53},[47,3768,188],{"class":101},[47,3770,114],{"class":53},[47,3772,3773],{"class":49,"line":68},[47,3774,120],{"class":101},[16,3776,3777],{},[25,3778,2820],{},[38,3780,3783],{"className":3781,"code":3782,"language":2826},[2824],"base := &BaseProcessor{}\nchain := NewLogging(NewUpperCase(NewTrim(base)))\nchain.Process(\"  hello world  \")\n→ [LOG] processing: \"  hello world  \"\n→ [LOG] result: \"HELLO WORLD\"\n→ \"HELLO WORLD\"\n",[20,3784,3782],{"__ignoreMap":43},[16,3786,3787],{},[25,3788,2833],{},[38,3790,3792],{"className":40,"code":3791,"language":42,"meta":43,"style":43},"package main\n\nimport (\n    \"fmt\"\n    \"strings\"\n)\n\ntype Processor interface {\n    Process(msg string) string\n}\n\n\u002F\u002F Базовый процессор — возвращает сообщение как есть\ntype BaseProcessor struct{}\n\nfunc (b *BaseProcessor) Process(msg string) string { return msg }\n\n\u002F\u002F Trim обёртка\ntype TrimProcessor struct{ next Processor }\n\nfunc NewTrim(next Processor) *TrimProcessor { return &TrimProcessor{next: next} }\n\nfunc (t *TrimProcessor) Process(msg string) string {\n    return t.next.Process(strings.TrimSpace(msg))\n}\n\n\u002F\u002F UpperCase обёртка\ntype UpperCaseProcessor struct{ next Processor }\n\nfunc NewUpperCase(next Processor) *UpperCaseProcessor {\n    return &UpperCaseProcessor{next: next}\n}\n\nfunc (u *UpperCaseProcessor) Process(msg string) string {\n    return u.next.Process(strings.ToUpper(msg))\n}\n\n\u002F\u002F Logging обёртка\ntype LoggingProcessor struct{ next Processor }\n\nfunc NewLogging(next Processor) *LoggingProcessor {\n    return &LoggingProcessor{next: next}\n}\n\nfunc (l *LoggingProcessor) Process(msg string) string {\n    fmt.Printf(\"[LOG] processing: %q\\n\", msg)\n    result := l.next.Process(msg)\n    fmt.Printf(\"[LOG] result: %q\\n\", result)\n    return result\n}\n\nfunc main() {\n    base := &BaseProcessor{}\n    chain := NewLogging(NewUpperCase(NewTrim(base)))\n    result := chain.Process(\"  hello world  \")\n    fmt.Println(result)\n}\n",[20,3793,3794,3800,3804,3810,3818,3827,3831,3835,3845,3859,3863,3867,3872,3883,3887,3923,3927,3932,3948,3952,3983,3987,4016,4034,4038,4042,4047,4062,4066,4087,4098,4102,4106,4134,4151,4156,4161,4167,4183,4188,4210,4221,4226,4231,4261,4281,4297,4316,4324,4329,4334,4343,4357,4380,4399,4409],{"__ignoreMap":43},[47,3795,3796,3798],{"class":49,"line":50},[47,3797,54],{"class":53},[47,3799,58],{"class":57},[47,3801,3802],{"class":49,"line":61},[47,3803,65],{"emptyLinePlaceholder":64},[47,3805,3806,3808],{"class":49,"line":68},[47,3807,71],{"class":53},[47,3809,2855],{"class":101},[47,3811,3812,3814,3816],{"class":49,"line":84},[47,3813,2860],{"class":74},[47,3815,78],{"class":57},[47,3817,81],{"class":74},[47,3819,3820,3822,3825],{"class":49,"line":89},[47,3821,2860],{"class":74},[47,3823,3824],{"class":57},"strings",[47,3826,81],{"class":74},[47,3828,3829],{"class":49,"line":105},[47,3830,761],{"class":101},[47,3832,3833],{"class":49,"line":117},[47,3834,65],{"emptyLinePlaceholder":64},[47,3836,3837,3839,3841,3843],{"class":49,"line":123},[47,3838,92],{"class":53},[47,3840,3750],{"class":57},[47,3842,98],{"class":53},[47,3844,102],{"class":101},[47,3846,3847,3849,3851,3853,3855,3857],{"class":49,"line":128},[47,3848,3759],{"class":57},[47,3850,733],{"class":101},[47,3852,3764],{"class":181},[47,3854,1161],{"class":53},[47,3856,188],{"class":101},[47,3858,114],{"class":53},[47,3860,3861],{"class":49,"line":141},[47,3862,120],{"class":101},[47,3864,3865],{"class":49,"line":149},[47,3866,65],{"emptyLinePlaceholder":64},[47,3868,3869],{"class":49,"line":154},[47,3870,3871],{"class":162},"\u002F\u002F Базовый процессор — возвращает сообщение как есть\n",[47,3873,3874,3876,3879,3881],{"class":49,"line":159},[47,3875,92],{"class":53},[47,3877,3878],{"class":57}," BaseProcessor",[47,3880,136],{"class":53},[47,3882,2031],{"class":101},[47,3884,3885],{"class":49,"line":166},[47,3886,65],{"emptyLinePlaceholder":64},[47,3888,3889,3891,3893,3896,3898,3901,3903,3906,3908,3910,3912,3914,3916,3918,3920],{"class":49,"line":172},[47,3890,175],{"class":53},[47,3892,178],{"class":101},[47,3894,3895],{"class":181},"b ",[47,3897,328],{"class":53},[47,3899,3900],{"class":57},"BaseProcessor",[47,3902,188],{"class":101},[47,3904,3905],{"class":57},"Process",[47,3907,733],{"class":101},[47,3909,3764],{"class":181},[47,3911,1161],{"class":53},[47,3913,188],{"class":101},[47,3915,196],{"class":53},[47,3917,985],{"class":101},[47,3919,988],{"class":53},[47,3921,3922],{"class":101}," msg }\n",[47,3924,3925],{"class":49,"line":201},[47,3926,65],{"emptyLinePlaceholder":64},[47,3928,3929],{"class":49,"line":210},[47,3930,3931],{"class":162},"\u002F\u002F Trim обёртка\n",[47,3933,3934,3936,3939,3941,3944,3946],{"class":49,"line":215},[47,3935,92],{"class":53},[47,3937,3938],{"class":57}," TrimProcessor",[47,3940,136],{"class":53},[47,3942,3943],{"class":101},"{ next ",[47,3945,3725],{"class":57},[47,3947,955],{"class":101},[47,3949,3950],{"class":49,"line":220},[47,3951,65],{"emptyLinePlaceholder":64},[47,3953,3954,3956,3959,3961,3964,3966,3968,3970,3972,3974,3976,3978,3980],{"class":49,"line":231},[47,3955,175],{"class":53},[47,3957,3958],{"class":57}," NewTrim",[47,3960,733],{"class":101},[47,3962,3963],{"class":181},"next",[47,3965,3750],{"class":57},[47,3967,188],{"class":101},[47,3969,328],{"class":53},[47,3971,3737],{"class":57},[47,3973,985],{"class":101},[47,3975,988],{"class":53},[47,3977,689],{"class":53},[47,3979,3737],{"class":57},[47,3981,3982],{"class":101},"{next: next} }\n",[47,3984,3985],{"class":49,"line":260},[47,3986,65],{"emptyLinePlaceholder":64},[47,3988,3989,3991,3993,3996,3998,4000,4002,4004,4006,4008,4010,4012,4014],{"class":49,"line":280},[47,3990,175],{"class":53},[47,3992,178],{"class":101},[47,3994,3995],{"class":181},"t ",[47,3997,328],{"class":53},[47,3999,3737],{"class":57},[47,4001,188],{"class":101},[47,4003,3905],{"class":57},[47,4005,733],{"class":101},[47,4007,3764],{"class":181},[47,4009,1161],{"class":53},[47,4011,188],{"class":101},[47,4013,196],{"class":53},[47,4015,102],{"class":101},[47,4017,4018,4020,4023,4025,4028,4031],{"class":49,"line":2529},[47,4019,204],{"class":53},[47,4021,4022],{"class":101}," t.next.",[47,4024,3905],{"class":57},[47,4026,4027],{"class":101},"(strings.",[47,4029,4030],{"class":57},"TrimSpace",[47,4032,4033],{"class":101},"(msg))\n",[47,4035,4036],{"class":49,"line":2544},[47,4037,120],{"class":101},[47,4039,4040],{"class":49,"line":2561},[47,4041,65],{"emptyLinePlaceholder":64},[47,4043,4044],{"class":49,"line":3159},[47,4045,4046],{"class":162},"\u002F\u002F UpperCase обёртка\n",[47,4048,4049,4051,4054,4056,4058,4060],{"class":49,"line":3164},[47,4050,92],{"class":53},[47,4052,4053],{"class":57}," UpperCaseProcessor",[47,4055,136],{"class":53},[47,4057,3943],{"class":101},[47,4059,3725],{"class":57},[47,4061,955],{"class":101},[47,4063,4064],{"class":49,"line":3171},[47,4065,65],{"emptyLinePlaceholder":64},[47,4067,4068,4070,4073,4075,4077,4079,4081,4083,4085],{"class":49,"line":3176},[47,4069,175],{"class":53},[47,4071,4072],{"class":57}," NewUpperCase",[47,4074,733],{"class":101},[47,4076,3963],{"class":181},[47,4078,3750],{"class":57},[47,4080,188],{"class":101},[47,4082,328],{"class":53},[47,4084,3733],{"class":57},[47,4086,102],{"class":101},[47,4088,4089,4091,4093,4095],{"class":49,"line":3181},[47,4090,204],{"class":53},[47,4092,689],{"class":53},[47,4094,3733],{"class":57},[47,4096,4097],{"class":101},"{next: next}\n",[47,4099,4100],{"class":49,"line":3190},[47,4101,120],{"class":101},[47,4103,4104],{"class":49,"line":3232},[47,4105,65],{"emptyLinePlaceholder":64},[47,4107,4108,4110,4112,4114,4116,4118,4120,4122,4124,4126,4128,4130,4132],{"class":49,"line":3260},[47,4109,175],{"class":53},[47,4111,178],{"class":101},[47,4113,182],{"class":181},[47,4115,328],{"class":53},[47,4117,3733],{"class":57},[47,4119,188],{"class":101},[47,4121,3905],{"class":57},[47,4123,733],{"class":101},[47,4125,3764],{"class":181},[47,4127,1161],{"class":53},[47,4129,188],{"class":101},[47,4131,196],{"class":53},[47,4133,102],{"class":101},[47,4135,4137,4139,4142,4144,4146,4149],{"class":49,"line":4136},34,[47,4138,204],{"class":53},[47,4140,4141],{"class":101}," u.next.",[47,4143,3905],{"class":57},[47,4145,4027],{"class":101},[47,4147,4148],{"class":57},"ToUpper",[47,4150,4033],{"class":101},[47,4152,4154],{"class":49,"line":4153},35,[47,4155,120],{"class":101},[47,4157,4159],{"class":49,"line":4158},36,[47,4160,65],{"emptyLinePlaceholder":64},[47,4162,4164],{"class":49,"line":4163},37,[47,4165,4166],{"class":162},"\u002F\u002F Logging обёртка\n",[47,4168,4170,4172,4175,4177,4179,4181],{"class":49,"line":4169},38,[47,4171,92],{"class":53},[47,4173,4174],{"class":57}," LoggingProcessor",[47,4176,136],{"class":53},[47,4178,3943],{"class":101},[47,4180,3725],{"class":57},[47,4182,955],{"class":101},[47,4184,4186],{"class":49,"line":4185},39,[47,4187,65],{"emptyLinePlaceholder":64},[47,4189,4191,4193,4196,4198,4200,4202,4204,4206,4208],{"class":49,"line":4190},40,[47,4192,175],{"class":53},[47,4194,4195],{"class":57}," NewLogging",[47,4197,733],{"class":101},[47,4199,3963],{"class":181},[47,4201,3750],{"class":57},[47,4203,188],{"class":101},[47,4205,328],{"class":53},[47,4207,3729],{"class":57},[47,4209,102],{"class":101},[47,4211,4213,4215,4217,4219],{"class":49,"line":4212},41,[47,4214,204],{"class":53},[47,4216,689],{"class":53},[47,4218,3729],{"class":57},[47,4220,4097],{"class":101},[47,4222,4224],{"class":49,"line":4223},42,[47,4225,120],{"class":101},[47,4227,4229],{"class":49,"line":4228},43,[47,4230,65],{"emptyLinePlaceholder":64},[47,4232,4234,4236,4238,4241,4243,4245,4247,4249,4251,4253,4255,4257,4259],{"class":49,"line":4233},44,[47,4235,175],{"class":53},[47,4237,178],{"class":101},[47,4239,4240],{"class":181},"l ",[47,4242,328],{"class":53},[47,4244,3729],{"class":57},[47,4246,188],{"class":101},[47,4248,3905],{"class":57},[47,4250,733],{"class":101},[47,4252,3764],{"class":181},[47,4254,1161],{"class":53},[47,4256,188],{"class":101},[47,4258,196],{"class":53},[47,4260,102],{"class":101},[47,4262,4264,4266,4268,4270,4273,4276,4278],{"class":49,"line":4263},45,[47,4265,263],{"class":101},[47,4267,3237],{"class":57},[47,4269,733],{"class":101},[47,4271,4272],{"class":74},"\"[LOG] processing: ",[47,4274,4275],{"class":336},"%q\\n",[47,4277,1561],{"class":74},[47,4279,4280],{"class":101},", msg)\n",[47,4282,4284,4287,4289,4292,4294],{"class":49,"line":4283},46,[47,4285,4286],{"class":101},"    result ",[47,4288,1062],{"class":53},[47,4290,4291],{"class":101}," l.next.",[47,4293,3905],{"class":57},[47,4295,4296],{"class":101},"(msg)\n",[47,4298,4300,4302,4304,4306,4309,4311,4313],{"class":49,"line":4299},47,[47,4301,263],{"class":101},[47,4303,3237],{"class":57},[47,4305,733],{"class":101},[47,4307,4308],{"class":74},"\"[LOG] result: ",[47,4310,4275],{"class":336},[47,4312,1561],{"class":74},[47,4314,4315],{"class":101},", result)\n",[47,4317,4319,4321],{"class":49,"line":4318},48,[47,4320,204],{"class":53},[47,4322,4323],{"class":101}," result\n",[47,4325,4327],{"class":49,"line":4326},49,[47,4328,120],{"class":101},[47,4330,4332],{"class":49,"line":4331},50,[47,4333,65],{"emptyLinePlaceholder":64},[47,4335,4337,4339,4341],{"class":49,"line":4336},51,[47,4338,175],{"class":53},[47,4340,225],{"class":57},[47,4342,228],{"class":101},[47,4344,4346,4349,4351,4353,4355],{"class":49,"line":4345},52,[47,4347,4348],{"class":101},"    base ",[47,4350,1062],{"class":53},[47,4352,689],{"class":53},[47,4354,3900],{"class":57},[47,4356,2031],{"class":101},[47,4358,4360,4363,4365,4367,4369,4372,4374,4377],{"class":49,"line":4359},53,[47,4361,4362],{"class":101},"    chain ",[47,4364,1062],{"class":53},[47,4366,4195],{"class":57},[47,4368,733],{"class":101},[47,4370,4371],{"class":57},"NewUpperCase",[47,4373,733],{"class":101},[47,4375,4376],{"class":57},"NewTrim",[47,4378,4379],{"class":101},"(base)))\n",[47,4381,4383,4385,4387,4390,4392,4394,4397],{"class":49,"line":4382},54,[47,4384,4286],{"class":101},[47,4386,1062],{"class":53},[47,4388,4389],{"class":101}," chain.",[47,4391,3905],{"class":57},[47,4393,733],{"class":101},[47,4395,4396],{"class":74},"\"  hello world  \"",[47,4398,761],{"class":101},[47,4400,4402,4404,4406],{"class":49,"line":4401},55,[47,4403,263],{"class":101},[47,4405,266],{"class":57},[47,4407,4408],{"class":101},"(result)\n",[47,4410,4412],{"class":49,"line":4411},56,[47,4413,120],{"class":101},[30,4415],{},[33,4417,4419],{"id":4418},"практика","Практика",[4421,4422,4426,4429,4454],"quiz",{"answer":4423,"id":4424,"xp":4425},"3","basics-interfaces-q1","10",[16,4427,4428],{},"Где обычно лучше объявлять небольшой интерфейс в Go?",[4430,4431,4432],"template",{"v-slot:options":43},[4433,4434,4435,4438,4444,4447],"ul",{},[1726,4436,4437],{},"В пакете, который производит конкретную структуру",[1726,4439,4440,4441],{},"В отдельном общем пакете ",[20,4442,4443],{},"interfaces",[1726,4445,4446],{},"В пакете потребителя, которому нужен минимальный контракт",[1726,4448,4449,4450,4453],{},"В ",[20,4451,4452],{},"main",", чтобы не создавать лишние файлы",[4430,4455,4456],{"v-slot:explanation":43},[16,4457,4458],{},"Идиома Go — определять интерфейс на стороне потребителя. Так контракт остаётся маленьким и описывает реальную потребность вызывающего кода, а производитель может возвращать конкретный тип.",[4460,4461,4465,4775],"predict",{"answer":4462,"id":4463,"xp":4464},"false\\nfalse\\ntrue\\n\u003Cnil>","basics-interfaces-p1","15",[4430,4466,4467],{"v-slot:code":43},[38,4468,4469],{"className":40,"code":3287,"language":42,"meta":43,"style":43},[20,4470,4471,4477,4481,4491,4495,4509,4513,4539,4543,4561,4571,4577,4593,4597,4603,4607,4611,4629,4635,4649,4653,4659,4663,4667,4675,4689,4703,4717,4721,4735,4749,4763,4771],{"__ignoreMap":43},[47,4472,4473,4475],{"class":49,"line":50},[47,4474,54],{"class":53},[47,4476,58],{"class":57},[47,4478,4479],{"class":49,"line":61},[47,4480,65],{"emptyLinePlaceholder":64},[47,4482,4483,4485,4487,4489],{"class":49,"line":68},[47,4484,71],{"class":53},[47,4486,75],{"class":74},[47,4488,78],{"class":57},[47,4490,81],{"class":74},[47,4492,4493],{"class":49,"line":84},[47,4494,65],{"emptyLinePlaceholder":64},[47,4496,4497,4499,4501,4503,4505,4507],{"class":49,"line":89},[47,4498,92],{"class":53},[47,4500,945],{"class":57},[47,4502,136],{"class":53},[47,4504,950],{"class":101},[47,4506,196],{"class":53},[47,4508,955],{"class":101},[47,4510,4511],{"class":49,"line":105},[47,4512,65],{"emptyLinePlaceholder":64},[47,4514,4515,4517,4519,4521,4523,4525,4527,4529,4531,4533,4535,4537],{"class":49,"line":117},[47,4516,175],{"class":53},[47,4518,178],{"class":101},[47,4520,968],{"class":181},[47,4522,328],{"class":53},[47,4524,973],{"class":57},[47,4526,188],{"class":101},[47,4528,978],{"class":57},[47,4530,111],{"class":101},[47,4532,196],{"class":53},[47,4534,985],{"class":101},[47,4536,988],{"class":53},[47,4538,991],{"class":101},[47,4540,4541],{"class":49,"line":123},[47,4542,65],{"emptyLinePlaceholder":64},[47,4544,4545,4547,4549,4551,4553,4555,4557,4559],{"class":49,"line":128},[47,4546,175],{"class":53},[47,4548,1002],{"class":57},[47,4550,733],{"class":101},[47,4552,3372],{"class":181},[47,4554,1599],{"class":53},[47,4556,188],{"class":101},[47,4558,1007],{"class":53},[47,4560,102],{"class":101},[47,4562,4563,4565,4567,4569],{"class":49,"line":141},[47,4564,234],{"class":53},[47,4566,1174],{"class":101},[47,4568,328],{"class":53},[47,4570,3391],{"class":57},[47,4572,4573,4575],{"class":49,"line":149},[47,4574,1184],{"class":53},[47,4576,3398],{"class":101},[47,4578,4579,4581,4583,4585,4587,4589,4591],{"class":49,"line":154},[47,4580,1198],{"class":101},[47,4582,663],{"class":53},[47,4584,689],{"class":53},[47,4586,973],{"class":57},[47,4588,1208],{"class":101},[47,4590,3413],{"class":74},[47,4592,120],{"class":101},[47,4594,4595],{"class":49,"line":159},[47,4596,1218],{"class":101},[47,4598,4599,4601],{"class":49,"line":166},[47,4600,204],{"class":53},[47,4602,3426],{"class":101},[47,4604,4605],{"class":49,"line":172},[47,4606,120],{"class":101},[47,4608,4609],{"class":49,"line":201},[47,4610,65],{"emptyLinePlaceholder":64},[47,4612,4613,4615,4617,4619,4621,4623,4625,4627],{"class":49,"line":210},[47,4614,175],{"class":53},[47,4616,3441],{"class":57},[47,4618,733],{"class":101},[47,4620,3372],{"class":181},[47,4622,1599],{"class":53},[47,4624,188],{"class":101},[47,4626,1007],{"class":53},[47,4628,102],{"class":101},[47,4630,4631,4633],{"class":49,"line":215},[47,4632,1184],{"class":53},[47,4634,3398],{"class":101},[47,4636,4637,4639,4641,4643,4645,4647],{"class":49,"line":220},[47,4638,1275],{"class":53},[47,4640,689],{"class":53},[47,4642,973],{"class":57},[47,4644,1208],{"class":101},[47,4646,3413],{"class":74},[47,4648,120],{"class":101},[47,4650,4651],{"class":49,"line":231},[47,4652,1218],{"class":101},[47,4654,4655,4657],{"class":49,"line":260},[47,4656,204],{"class":53},[47,4658,2469],{"class":336},[47,4660,4661],{"class":49,"line":280},[47,4662,120],{"class":101},[47,4664,4665],{"class":49,"line":2529},[47,4666,65],{"emptyLinePlaceholder":64},[47,4668,4669,4671,4673],{"class":49,"line":2544},[47,4670,175],{"class":53},[47,4672,225],{"class":57},[47,4674,228],{"class":101},[47,4676,4677,4679,4681,4683,4685,4687],{"class":49,"line":2561},[47,4678,3504],{"class":101},[47,4680,1062],{"class":53},[47,4682,1002],{"class":57},[47,4684,733],{"class":101},[47,4686,3513],{"class":336},[47,4688,761],{"class":101},[47,4690,4691,4693,4695,4697,4699,4701],{"class":49,"line":3159},[47,4692,3520],{"class":101},[47,4694,1062],{"class":53},[47,4696,1002],{"class":57},[47,4698,733],{"class":101},[47,4700,3529],{"class":336},[47,4702,761],{"class":101},[47,4704,4705,4707,4709,4711,4713,4715],{"class":49,"line":3164},[47,4706,3536],{"class":101},[47,4708,1062],{"class":53},[47,4710,3441],{"class":57},[47,4712,733],{"class":101},[47,4714,3513],{"class":336},[47,4716,761],{"class":101},[47,4718,4719],{"class":49,"line":3171},[47,4720,65],{"emptyLinePlaceholder":64},[47,4722,4723,4725,4727,4729,4731,4733],{"class":49,"line":3176},[47,4724,263],{"class":101},[47,4726,266],{"class":57},[47,4728,3559],{"class":101},[47,4730,1079],{"class":53},[47,4732,1025],{"class":336},[47,4734,761],{"class":101},[47,4736,4737,4739,4741,4743,4745,4747],{"class":49,"line":3181},[47,4738,263],{"class":101},[47,4740,266],{"class":57},[47,4742,3574],{"class":101},[47,4744,1079],{"class":53},[47,4746,1025],{"class":336},[47,4748,761],{"class":101},[47,4750,4751,4753,4755,4757,4759,4761],{"class":49,"line":3190},[47,4752,263],{"class":101},[47,4754,266],{"class":57},[47,4756,3589],{"class":101},[47,4758,1079],{"class":53},[47,4760,1025],{"class":336},[47,4762,761],{"class":101},[47,4764,4765,4767,4769],{"class":49,"line":3232},[47,4766,263],{"class":101},[47,4768,266],{"class":57},[47,4770,3604],{"class":101},[47,4772,4773],{"class":49,"line":3260},[47,4774,120],{"class":101},[4430,4776,4777],{"v-slot:hint":43},[16,4778,4779,4782,4783,4785],{},[20,4780,4781],{},"err1"," содержит тип ",[20,4784,1111],{}," внутри интерфейса, даже когда data равна nil. Такой интерфейс уже не равен nil.",[4787,4788,4792,4808,5211],"code-task",{"expected":4789,"id":4790,"xp":4791},"102.54","basics-interfaces-ct1","20",[16,4793,4794,4795,896,4797,4799,4800,896,4802,4804,4805,411],{},"Реализуй ",[20,4796,2968],{},[20,4798,3005],{}," для ",[20,4801,2765],{},[20,4803,2768],{},", а затем посчитай суммарную площадь через слайс интерфейсов ",[20,4806,4807],{},"[]Shape",[4430,4809,4810],{"v-slot:template":43},[38,4811,4813],{"className":40,"code":4812,"language":42,"meta":43,"style":43},"package main\n\nimport (\n    \"fmt\"\n    \"math\"\n)\n\ntype Shape interface {\n    Area() float64\n    Perimeter() float64\n}\n\ntype Circle struct{ Radius float64 }\ntype Rectangle struct{ Width, Height float64 }\n\nfunc (c Circle) Area() float64 {\n    \u002F\u002F твой код здесь\n    return 0\n}\n\nfunc (c Circle) Perimeter() float64 {\n    \u002F\u002F твой код здесь\n    return 0\n}\n\nfunc (r Rectangle) Area() float64 {\n    \u002F\u002F твой код здесь\n    return 0\n}\n\nfunc (r Rectangle) Perimeter() float64 {\n    \u002F\u002F твой код здесь\n    return 0\n}\n\nfunc totalArea(shapes []Shape) float64 {\n    total := 0.0\n    for _, shape := range shapes {\n        total += shape.Area()\n    }\n    return total\n}\n\nfunc main() {\n    shapes := []Shape{Circle{Radius: 5}, Rectangle{Width: 4, Height: 6}}\n    fmt.Printf(\"%.2f\\n\", totalArea(shapes))\n}\n",[20,4814,4815,4821,4825,4831,4839,4847,4851,4855,4865,4873,4881,4885,4889,4903,4917,4921,4941,4946,4952,4956,4960,4980,4984,4990,4994,4998,5018,5022,5028,5032,5036,5056,5060,5066,5070,5074,5094,5102,5115,5128,5132,5138,5142,5146,5154,5186,5207],{"__ignoreMap":43},[47,4816,4817,4819],{"class":49,"line":50},[47,4818,54],{"class":53},[47,4820,58],{"class":57},[47,4822,4823],{"class":49,"line":61},[47,4824,65],{"emptyLinePlaceholder":64},[47,4826,4827,4829],{"class":49,"line":68},[47,4828,71],{"class":53},[47,4830,2855],{"class":101},[47,4832,4833,4835,4837],{"class":49,"line":84},[47,4834,2860],{"class":74},[47,4836,78],{"class":57},[47,4838,81],{"class":74},[47,4840,4841,4843,4845],{"class":49,"line":89},[47,4842,2860],{"class":74},[47,4844,2871],{"class":57},[47,4846,81],{"class":74},[47,4848,4849],{"class":49,"line":105},[47,4850,761],{"class":101},[47,4852,4853],{"class":49,"line":117},[47,4854,65],{"emptyLinePlaceholder":64},[47,4856,4857,4859,4861,4863],{"class":49,"line":123},[47,4858,92],{"class":53},[47,4860,2788],{"class":57},[47,4862,98],{"class":53},[47,4864,102],{"class":101},[47,4866,4867,4869,4871],{"class":49,"line":128},[47,4868,2797],{"class":57},[47,4870,111],{"class":101},[47,4872,2802],{"class":53},[47,4874,4875,4877,4879],{"class":49,"line":141},[47,4876,2807],{"class":57},[47,4878,111],{"class":101},[47,4880,2802],{"class":53},[47,4882,4883],{"class":49,"line":149},[47,4884,120],{"class":101},[47,4886,4887],{"class":49,"line":154},[47,4888,65],{"emptyLinePlaceholder":64},[47,4890,4891,4893,4895,4897,4899,4901],{"class":49,"line":159},[47,4892,92],{"class":53},[47,4894,2922],{"class":57},[47,4896,136],{"class":53},[47,4898,2927],{"class":101},[47,4900,2930],{"class":53},[47,4902,955],{"class":101},[47,4904,4905,4907,4909,4911,4913,4915],{"class":49,"line":166},[47,4906,92],{"class":53},[47,4908,2939],{"class":57},[47,4910,136],{"class":53},[47,4912,2944],{"class":101},[47,4914,2930],{"class":53},[47,4916,955],{"class":101},[47,4918,4919],{"class":49,"line":172},[47,4920,65],{"emptyLinePlaceholder":64},[47,4922,4923,4925,4927,4929,4931,4933,4935,4937,4939],{"class":49,"line":201},[47,4924,175],{"class":53},[47,4926,178],{"class":101},[47,4928,2961],{"class":181},[47,4930,2765],{"class":57},[47,4932,188],{"class":101},[47,4934,2968],{"class":57},[47,4936,111],{"class":101},[47,4938,2930],{"class":53},[47,4940,102],{"class":101},[47,4942,4943],{"class":49,"line":210},[47,4944,4945],{"class":162},"    \u002F\u002F твой код здесь\n",[47,4947,4948,4950],{"class":49,"line":215},[47,4949,204],{"class":53},[47,4951,1798],{"class":336},[47,4953,4954],{"class":49,"line":220},[47,4955,120],{"class":101},[47,4957,4958],{"class":49,"line":231},[47,4959,65],{"emptyLinePlaceholder":64},[47,4961,4962,4964,4966,4968,4970,4972,4974,4976,4978],{"class":49,"line":260},[47,4963,175],{"class":53},[47,4965,178],{"class":101},[47,4967,2961],{"class":181},[47,4969,2765],{"class":57},[47,4971,188],{"class":101},[47,4973,3005],{"class":57},[47,4975,111],{"class":101},[47,4977,2930],{"class":53},[47,4979,102],{"class":101},[47,4981,4982],{"class":49,"line":280},[47,4983,4945],{"class":162},[47,4985,4986,4988],{"class":49,"line":2529},[47,4987,204],{"class":53},[47,4989,1798],{"class":336},[47,4991,4992],{"class":49,"line":2544},[47,4993,120],{"class":101},[47,4995,4996],{"class":49,"line":2561},[47,4997,65],{"emptyLinePlaceholder":64},[47,4999,5000,5002,5004,5006,5008,5010,5012,5014,5016],{"class":49,"line":3159},[47,5001,175],{"class":53},[47,5003,178],{"class":101},[47,5005,3037],{"class":181},[47,5007,2768],{"class":57},[47,5009,188],{"class":101},[47,5011,2968],{"class":57},[47,5013,111],{"class":101},[47,5015,2930],{"class":53},[47,5017,102],{"class":101},[47,5019,5020],{"class":49,"line":3164},[47,5021,4945],{"class":162},[47,5023,5024,5026],{"class":49,"line":3171},[47,5025,204],{"class":53},[47,5027,1798],{"class":336},[47,5029,5030],{"class":49,"line":3176},[47,5031,120],{"class":101},[47,5033,5034],{"class":49,"line":3181},[47,5035,65],{"emptyLinePlaceholder":64},[47,5037,5038,5040,5042,5044,5046,5048,5050,5052,5054],{"class":49,"line":3190},[47,5039,175],{"class":53},[47,5041,178],{"class":101},[47,5043,3037],{"class":181},[47,5045,2768],{"class":57},[47,5047,188],{"class":101},[47,5049,3005],{"class":57},[47,5051,111],{"class":101},[47,5053,2930],{"class":53},[47,5055,102],{"class":101},[47,5057,5058],{"class":49,"line":3232},[47,5059,4945],{"class":162},[47,5061,5062,5064],{"class":49,"line":3260},[47,5063,204],{"class":53},[47,5065,1798],{"class":336},[47,5067,5068],{"class":49,"line":4136},[47,5069,120],{"class":101},[47,5071,5072],{"class":49,"line":4153},[47,5073,65],{"emptyLinePlaceholder":64},[47,5075,5076,5078,5080,5082,5084,5086,5088,5090,5092],{"class":49,"line":4158},[47,5077,175],{"class":53},[47,5079,3105],{"class":57},[47,5081,733],{"class":101},[47,5083,3110],{"class":181},[47,5085,738],{"class":101},[47,5087,2761],{"class":57},[47,5089,188],{"class":101},[47,5091,2930],{"class":53},[47,5093,102],{"class":101},[47,5095,5096,5098,5100],{"class":49,"line":4163},[47,5097,1793],{"class":101},[47,5099,1062],{"class":53},[47,5101,3129],{"class":336},[47,5103,5104,5106,5109,5111,5113],{"class":49,"line":4169},[47,5105,1803],{"class":53},[47,5107,5108],{"class":101}," _, shape ",[47,5110,1062],{"class":53},[47,5112,1811],{"class":53},[47,5114,3143],{"class":101},[47,5116,5117,5119,5121,5124,5126],{"class":49,"line":4185},[47,5118,1819],{"class":101},[47,5120,1822],{"class":53},[47,5122,5123],{"class":101}," shape.",[47,5125,2968],{"class":57},[47,5127,1067],{"class":101},[47,5129,5130],{"class":49,"line":4190},[47,5131,1218],{"class":101},[47,5133,5134,5136],{"class":49,"line":4212},[47,5135,204],{"class":53},[47,5137,1844],{"class":101},[47,5139,5140],{"class":49,"line":4223},[47,5141,120],{"class":101},[47,5143,5144],{"class":49,"line":4228},[47,5145,65],{"emptyLinePlaceholder":64},[47,5147,5148,5150,5152],{"class":49,"line":4233},[47,5149,175],{"class":53},[47,5151,225],{"class":57},[47,5153,228],{"class":101},[47,5155,5156,5158,5160,5162,5164,5166,5168,5170,5172,5174,5176,5178,5180,5182,5184],{"class":49,"line":4263},[47,5157,3193],{"class":101},[47,5159,1062],{"class":53},[47,5161,738],{"class":101},[47,5163,2761],{"class":57},[47,5165,1208],{"class":101},[47,5167,2765],{"class":57},[47,5169,3206],{"class":101},[47,5171,3209],{"class":336},[47,5173,3212],{"class":101},[47,5175,2768],{"class":57},[47,5177,3217],{"class":101},[47,5179,3220],{"class":336},[47,5181,3223],{"class":101},[47,5183,3226],{"class":336},[47,5185,3229],{"class":101},[47,5187,5188,5190,5192,5194,5196,5198,5200,5202,5204],{"class":49,"line":4283},[47,5189,263],{"class":101},[47,5191,3237],{"class":57},[47,5193,733],{"class":101},[47,5195,1561],{"class":74},[47,5197,3244],{"class":336},[47,5199,1561],{"class":74},[47,5201,611],{"class":101},[47,5203,3251],{"class":57},[47,5205,5206],{"class":101},"(shapes))\n",[47,5208,5209],{"class":49,"line":4299},[47,5210,120],{"class":101},[4430,5212,5213],{"v-slot:hints":43},[4433,5214,5215,5221,5227],{},[1726,5216,5217,5218],{},"Площадь круга: ",[20,5219,5220],{},"math.Pi * c.Radius * c.Radius",[1726,5222,5223,5224],{},"Периметр круга: ",[20,5225,5226],{},"2 * math.Pi * c.Radius",[1726,5228,5229,5230],{},"Площадь прямоугольника: ",[20,5231,5232],{},"r.Width * r.Height",[5234,5235,5236],"style",{},"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 .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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}",{"title":43,"searchDepth":61,"depth":61,"links":5238},[5239,5240,5245,5246,5247,5248,5249,5250,5251,5256,5257],{"id":35,"depth":61,"text":36},{"id":350,"depth":61,"text":351,"children":5241},[5242,5244],{"id":362,"depth":68,"text":5243},"eface — пустой интерфейс (interface{} \u002F any)",{"id":436,"depth":68,"text":437},{"id":599,"depth":61,"text":600},{"id":705,"depth":61,"text":706},{"id":872,"depth":61,"text":873},{"id":1307,"depth":61,"text":1308},{"id":1482,"depth":61,"text":1483},{"id":1717,"depth":61,"text":1718},{"id":1933,"depth":61,"text":1934,"children":5252},[5253,5254,5255],{"id":1937,"depth":68,"text":1938},{"id":2078,"depth":68,"text":2079},{"id":2295,"depth":68,"text":2296},{"id":2568,"depth":61,"text":2569},{"id":4418,"depth":61,"text":4419},1781458319388]