<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Petrovichev Sergey</title>
    <description>The latest articles on Forem by Petrovichev Sergey (@petrovichevsergey).</description>
    <link>https://forem.com/petrovichevsergey</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F203847%2Ff32077fc-de23-4693-8954-5ec973f4a0e4.jpeg</url>
      <title>Forem: Petrovichev Sergey</title>
      <link>https://forem.com/petrovichevsergey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/petrovichevsergey"/>
    <language>en</language>
    <item>
      <title>Функциональные  опции в Go: реализация шаблона опций в Golang</title>
      <dc:creator>Petrovichev Sergey</dc:creator>
      <pubDate>Mon, 30 Aug 2021 09:51:10 +0000</pubDate>
      <link>https://forem.com/petrovichevsergey/-fjh</link>
      <guid>https://forem.com/petrovichevsergey/-fjh</guid>
      <description>&lt;h1&gt;
  
  
  Функциональные опции
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Оригинал статьи автора Soham Kamani &lt;a href="https://www.sohamkamani.com/golang/options-pattern/"&gt;здесь&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;В этом посте рассказывается о том, какие функциональные опции есть в Go и как мы можем использовать шаблон "опции" для их реализации. Функциональные опции имеют форму дополнительных аргументов функции, которые расширяют или изменяют ее поведение. Вот пример, в котором используются функциональные параметры для создания новой структуры House:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHouse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;WithConcrete&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;WithoutFireplace&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Здесь NewHouse - это метод-конструктор. WithConcrete и WithFireplace - это параметры, передаваемые конструктору для изменения возвращаемого значения.&lt;/p&gt;

&lt;p&gt;Вскоре мы увидим, почему WithConcrete и WithFireplace называются «функциональными» опциями и чем они полезны по сравнению с обычными аргументами функций. &lt;/p&gt;

&lt;h2&gt;
  
  
  Определение конструктора
&lt;/h2&gt;

&lt;p&gt;Во-первых, давайте определим структуру, для которой мы создадим опции:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;House&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Material&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;HasFireplace&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;Floors&lt;/span&gt;       &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// `NewHouse` это метод-конструктор для `*House`&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewHouse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;defaultFloors&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;defaultHasFireplace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="n"&gt;defaultMaterial&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"wood"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Material&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;defaultMaterial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;HasFireplace&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;defaultHasFireplace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Floors&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;defaultFloors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Дом может быть построен из определенного материала, может иметь определенное количество этажей и, при желании, может содержать камин. Конструктор NewHouse возвращает нам указатель на структуру House по умолчанию с некоторыми значениями по умолчанию для всех его атрибутов. Обычно нам нужно сначала построить дом, а затем изменить его значения, если нам нужен другой вариант. С помощью функциональных опций мы можем предоставить список модификаций самого конструктора. &lt;/p&gt;

&lt;h2&gt;
  
  
  Определение функциональных опций
&lt;/h2&gt;

&lt;p&gt;Давайте определим тип функции, который принимает указатель на House:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HouseOption&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Это сигнатура наших функциональных опций. Давайте определим некоторые функциональные параметры, которые изменяют экземпляр *House:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WithConcrete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;HouseOption&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Material&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"concrete"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WithoutFireplace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;HouseOption&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasFireplace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Каждая из вышеперечисленных функций является «конструктором параметров» и возвращает другую функцию, которая принимает *House в качестве аргумента и ничего не возвращает. Мы видим, что возвращенные функции изменяют предоставленный экземпляр *House. Мы даже можем добавить аргументы в конструкторы параметров, чтобы изменить возвращаемые параметры:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WithFloors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;floors&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;HouseOption&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Floors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;floors&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Это вернет опцию, которая изменяет количество этажей в доме в соответствии с аргументом, заданным конструктору опции WithFloors. &lt;/p&gt;

&lt;h2&gt;
  
  
  Добавление функциональных опций в наш конструктор
&lt;/h2&gt;

&lt;p&gt;Теперь мы можем включить функциональные опции в наш конструктор:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// NewHouse теперь принимает слайс опций в качестве аргументов&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewHouse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="n"&gt;HouseOption&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;defaultFloors&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;defaultHasFireplace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="n"&gt;defaultMaterial&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"wood"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;House&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Material&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;defaultMaterial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;HasFireplace&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;defaultHasFireplace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Floors&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;defaultFloors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Применяем в цикле каждую опцию&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Call the option giving the instantiated&lt;/span&gt;
        &lt;span class="c"&gt;// *House as the argument&lt;/span&gt;
        &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// вернуть измененный экземпляр House&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Конструктор теперь принимает список любого количества аргументов функциональных опций, каждый элемент которого затем применяет к экземпляру *House перед его возвратом. Возвращаясь к первому примеру, теперь мы можем понять, что делают эти опции:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHouse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;WithConcrete&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;WithoutFireplace&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;WithFloors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Вы можете сами попробовать пример кода &lt;a href="https://play.golang.org/p/wfgJV9UWtB-"&gt;здесь&lt;/a&gt;!!!&lt;/p&gt;

&lt;h2&gt;
  
  
  Преимущества использования паттерна "функциональные опции"
&lt;/h2&gt;

&lt;p&gt;Теперь, когда мы увидели, как реализовать шаблон опций, давайте посмотрим, почему мы хотели бы использовать функциональные опции. &lt;/p&gt;

&lt;h4&gt;
  
  
  Наявность
&lt;/h4&gt;

&lt;p&gt;Вместо того, чтобы изменять *House следующим образом:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHouse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Material&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"concrete"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;мы можем явно указать строительный материал в самом конструкторе:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHouse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WithConcrete&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Это помогает нам четко указать строковое обозначение материала. Предыдущий пример позволяет пользователю делать опечатки и раскрывает внутреннюю часть экземпляра *House.&lt;/p&gt;

&lt;h2&gt;
  
  
  Расширяемость
&lt;/h2&gt;

&lt;p&gt;В случае, если мы действительно хотим предоставить пользователю расширяемость, мы всегда можем предоставить аргументы нашему конструктору опций. Например, поскольку у нас может быть любое количество этажей в нашем доме, возможность добавления этажей в дом может быть создана путем предоставления аргумента для количества этажей:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHouse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WithFloors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Порядок аргументов
&lt;/h2&gt;

&lt;p&gt;При использовании функциональных опций порядок их не имеет значения. Это дает нам большую гибкость по сравнению с обычными аргументами функции (которые должны быть в правильном порядке). Кроме того, мы можем предоставить любое количество вариантов. При использовании функций с обычными аргументами мы должны предоставить все аргументы:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;/*
Как выглядел бы `NewHouse`, если бы мы использовали обычные аргументы 
функции. Нам всегда нужно было бы предоставлять все три аргумента, 
неважно какие.
*/&lt;/span&gt;
&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHouse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"concrete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Итак, теперь, когда вы узнали о функциональных опциях, можете ли вы придумать, как можно улучшить уже существующий код? Видите ли вы какие-либо другие варианты использования или предостережения в использовании, которые я упустил? Дай мне знать в комментариях! Вот еще несколько шаблонов проектирования Golang, которые &lt;a href="https://www.sohamkamani.com/"&gt;я&lt;/a&gt;  рассмотрел:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.sohamkamani.com/golang/command-pattern/"&gt;Паттерн команда&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.sohamkamani.com/golang/2018-06-20-golang-factory-patterns/"&gt;Паттерн фабрика&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.sohamkamani.com/golang/enums/"&gt;Перечисления&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Как создать свое первое веб-приложение с помощью Go</title>
      <dc:creator>Petrovichev Sergey</dc:creator>
      <pubDate>Fri, 08 Nov 2019 14:57:43 +0000</pubDate>
      <link>https://forem.com/petrovichevsergey/go-49h</link>
      <guid>https://forem.com/petrovichevsergey/go-49h</guid>
      <description>&lt;h1&gt;
  
  
  Как создать свое первое веб-приложение с помощью Go
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Эта статья является переводом статьи "How to build your first web application with Go" автора Ayooluwa Isaiah, &lt;a href="https://freshman.tech/web-development-with-go/"&gt;ссылка на оригинал&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Это руководство к вашему первому веб-приложению на Go. Мы создадим &lt;a href="https://freshman-news.herokuapp.com/"&gt;новостное приложение&lt;/a&gt;, которое использует &lt;a href="https://newsapi.org/"&gt;News API&lt;/a&gt; для получения новостных статей по определенной теме, и развернём его на продакшн сервере в конце.&lt;/p&gt;

&lt;p&gt;Вы можете найти полный код, используемый для этого урока в этом  &lt;a href="https://github.com/Freshman-tech/news-demo"&gt;GitHub репозитории&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Требования
&lt;/h2&gt;

&lt;p&gt;Единственное требование для этого задания - чтобы на вашем компьютере был &lt;a href="(https://golang.org/doc/install)"&gt;установлен Go&lt;/a&gt;, и вы немного знакомы с его синтаксисом и конструкциями. Версия Go, которую я использовал при создании приложения, также является самой последней на момент написания: &lt;strong&gt;1.12.9&lt;/strong&gt;. Чтобы просмотреть установленную версию Go, используйте команду &lt;code&gt;go version&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Если вы считаете это задание слишком сложным для вас, перейдите к моему предыдущему &lt;a href="https://freshman.tech/golang-guess/"&gt;вводному уроку&lt;/a&gt; по языку, который должен помочь вам освоиться.&lt;/p&gt;

&lt;h2&gt;
  
  
  Итак, начнем!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Freshman-tech/news-demo-starter-files"&gt;Клонируем репозиторий стартовых файлов на GitHub&lt;/a&gt; и &lt;code&gt;cd&lt;/code&gt; в созданный каталог. У нас есть три основных файла: В файле &lt;code&gt;main.go&lt;/code&gt; мы напишем весь код Go для этого задания. Файл &lt;code&gt;index.html&lt;/code&gt; - это шаблон, который будет отправлен в браузер, а &lt;code&gt;стили&lt;/code&gt; для приложения находятся в &lt;code&gt;assets/styles.css&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Создадим базовый веб-сервер
&lt;/h2&gt;

&lt;p&gt;Давайте начнем с создания базового сервера, который отправляет текст «Hello World!» в браузер при выполнении запроса GET к корню сервера. Измените ваш файл &lt;code&gt;main.go&lt;/code&gt; так, чтобы он выглядел следующим образом:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"3000"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Первая строка &lt;code&gt;package main&lt;/code&gt; - декларирует, что код в файле &lt;code&gt;main.go&lt;/code&gt; принадлежит главному пакету. После этого мы импортировали пакет &lt;code&gt;net/http&lt;/code&gt;, который предоставляет реализации клиента и сервера HTTP для использования в нашем приложении. Этот пакет является частью стандартной библиотеки и входит в каждую установку Go.&lt;/p&gt;

&lt;p&gt;В функции &lt;code&gt;main&lt;/code&gt;,  &lt;code&gt;http.NewServeMux()&lt;/code&gt; создает новый мультиплексор HTTP-запросов и присваивает его переменной &lt;code&gt;mux&lt;/code&gt;. По сути, мультиплексор запросов сопоставляет URL-адрес входящих запросов со списком зарегистрированных путей и вызывает соответствующий обработчик для пути всякий раз, когда найдено совпадение.&lt;/p&gt;

&lt;p&gt;Далее мы регистрируем нашу первую функцию-обработчик для корневого пути &lt;code&gt;/&lt;/code&gt;. Эта функция-обработчик является вторым аргументом для &lt;code&gt;HandleFunc&lt;/code&gt; и всегда имеет сигнатуру &lt;code&gt;func (w http.ResponseWriter, r * http.Request)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Если вы посмотрите на функцию &lt;code&gt;indexHandler&lt;/code&gt;, вы увидите, что она имеет именно такую сигнатуру, что делает ее действительным вторым аргументом для &lt;code&gt;HandleFunc&lt;/code&gt;. Параметр &lt;code&gt;w&lt;/code&gt; - это структура, которую мы используем для отправки ответов на HTTP-запрос. Она реализует метод &lt;code&gt;Write()&lt;/code&gt;, который принимает слайс байтов и записывает  объединенные данные как часть HTTP-ответа.&lt;/p&gt;

&lt;p&gt;С другой стороны, параметр &lt;code&gt;r&lt;/code&gt; представляет HTTP-запрос, полученный от клиента. Это то, как мы получаем доступ к данным, отправляемым веб-браузером на сервере. Мы еще не используем его здесь, но мы точно будем использовать его позже.&lt;/p&gt;

&lt;p&gt;Наконец, у нас есть метод &lt;code&gt;http.ListenAndServe()&lt;/code&gt;, который запускает сервер на порту 3000, если порт не установлен окружением. Не стесняйтесь использовать другой порт, если 3000 используется на вашем компьютере.&lt;/p&gt;

&lt;p&gt;Затем скомпилируйте и выполните код, который вы только что написали:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Если вы перейдете на &lt;a href="http://localhost:3000/"&gt;http: // localhost: 3000&lt;/a&gt; в своем браузере, вы должны увидеть текст «Hello World!».&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566453173/Screenshot_from_2019-08-22_06-52-26.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PXocqAOx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566453173/Screenshot_from_2019-08-22_06-52-26.png" alt="Brave browser showing Hello World text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Шаблоны в Go
&lt;/h2&gt;

&lt;p&gt;Давайте рассмотрим основы шаблонизации в Go. Если вы знакомы с шаблонами на других языках, это должно быть достаточно просто для понимания.&lt;/p&gt;

&lt;p&gt;Шаблоны предоставляют простой способ настроить вывод вашего веб-приложения в зависимости от маршрута без необходимости писать один и тот же код в разных местах. Например, мы можем создать шаблон для панели навигации и использовать его на всех страницах сайта, не дублируя код. Кроме того, мы также получаем возможность добавить некоторую базовую логику на наши веб-страницы.&lt;/p&gt;

&lt;p&gt;Go предоставляет две библиотеки шаблонов в своей стандартной библиотеке: &lt;code&gt;text/template&lt;/code&gt; и &lt;code&gt;html/template&lt;/code&gt;. Оба предоставляют один и тот же интерфейс, однако пакет &lt;code&gt;html/template&lt;/code&gt; используется для генерации HTML-вывода, который защищен от инъекций кода, поэтому мы будем использовать его здесь.&lt;/p&gt;

&lt;p&gt;Импортируйте этот пакет в ваш файл &lt;code&gt;main.go&lt;/code&gt; и используйте его следующим образом:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"html/template"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tpl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"index.html"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"3000"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tpl&lt;/code&gt; - переменная уровня пакета, которая указывает на определение шаблона из предоставленных файлов. Вызов &lt;code&gt;template.ParseFiles&lt;/code&gt; анализирует файл&lt;code&gt;index.html&lt;/code&gt; в корне каталога нашего проекта и проверяет его на валидность.&lt;/p&gt;

&lt;p&gt;Мы оборачиваем вызов &lt;code&gt;template.ParseFiles&lt;/code&gt; в &lt;code&gt;template.Must&lt;/code&gt;, чтобы код вызывал панику при возникновении ошибки. Причина, по которой мы паникуем здесь вместо того, чтобы пытаться обработать ошибку, заключается в том, что нет смысла продолжать выполнение кода, если у нас невалидный шаблон. Это проблема, которая должна быть устранена перед попыткой перезапустить сервер.&lt;/p&gt;

&lt;p&gt;В функции &lt;code&gt;indexHandler&lt;/code&gt; мы выполняем созданный ранее шаблон, предоставляя два аргумента: куда мы хотим записать выходные данные и данные, которые мы хотим передать в шаблон.&lt;/p&gt;

&lt;p&gt;В приведенном выше случае мы записываем выходные данные в интерфейс &lt;code&gt;ResponseWriter&lt;/code&gt; и, поскольку у нас нет никаких данных для передачи в наш шаблон в настоящее время, в качестве второго аргумента передается &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Остановите запущенный процесс в вашем терминале с помощью Ctrl-C и запустите его снова с помощью &lt;code&gt;go run main.go&lt;/code&gt;, затем обновите ваш браузер. Вы должны увидеть текст «News App Demo» на странице, как показано ниже:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566454096/Screenshot_from_2019-08-22_07-08-05.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PTLlGWax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566454096/Screenshot_from_2019-08-22_07-08-05.png" alt="Brave browser showing News App Demo Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Добавляем панель навигации на страницу
&lt;/h2&gt;

&lt;p&gt;Замените содержимое тега &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; в вашем файле index.html, как показано ниже:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;News Demo&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;autofocus&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"search-input"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;
      &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter a news topic"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://github.com/freshman-tech/news"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button
      github-button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;View on Github&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Затем перезагрузите сервер и обновите ваш браузер. Вы должны увидеть что-то похожее на это:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566454745/Screenshot_from_2019-08-22_07-18-52.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QhoTQOGE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566454745/Screenshot_from_2019-08-22_07-18-52.png" alt="Browser showing unstyled navigation bar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Работа со статическими файлами
&lt;/h2&gt;

&lt;p&gt;Обратите внимание, что панель навигации, которую мы добавили выше, не имеет стилей, несмотря на тот факт, что мы уже указали их в &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; нашего документа.&lt;/p&gt;

&lt;p&gt;Это потому, что путь &lt;code&gt;/&lt;/code&gt; фактически совпадает со всеми путями, которые не обрабатываются в другом месте. Поэтому, если вы перейдете на &lt;a href="http://localhost:3000/assets/style.css"&gt;http://localhost:3000/assets/style.css&lt;/a&gt;, вы все равно получите домашнюю страницу News Demo вместо файла CSS, потому что маршрут &lt;code&gt;/assets/style.css&lt;/code&gt; не был объявлен специально.&lt;/p&gt;

&lt;p&gt;Но необходимость объявлять явные обработчики для всех наших статических файлов нереальна и не может масштабироваться. К счастью, мы можем создать один обработчик для обслуживания всех статических ресурсов.&lt;/p&gt;

&lt;p&gt;Первое, что нужно сделать, - создать экземпляр объекта файлового сервера, передав каталог, в котором находятся все наши статические файлы:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Далее нам нужно указать нашему маршрутизатору использовать этот объект файлового сервера для всех путей, начинающихся с префикса &lt;code&gt;/assets/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/assets/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/assets/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Теперь всё вместе:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// main.go&lt;/span&gt;

&lt;span class="c"&gt;// начало файла&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"3000"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Добавьте следующие две строки&lt;/span&gt;
    &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/assets/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/assets/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Перезагрузите сервер и обновите браузер. Стили должны включиться, как показано ниже:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566455131/Screenshot_from_2019-08-22_07-25-09.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FsdhbL_O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566455131/Screenshot_from_2019-08-22_07-25-09.png" alt="Brave browser showing styled navigation bar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Создаем роут /search
&lt;/h2&gt;

&lt;p&gt;Давайте создадим роут, который обрабатывает поисковые запросы для новостных статей. Мы будем использовать &lt;a href="https://newsapi.org/"&gt;News API&lt;/a&gt; для обработки запросов, поэтому вам нужно зарегистрироваться для получения бесплатного ключа API &lt;a href="https://newsapi.org/register"&gt;здесь&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Этот маршрут ожидает два параметра запроса: &lt;code&gt;q&lt;/code&gt; представляет запрос пользователя, а &lt;code&gt;page&lt;/code&gt; используется для пролистывания результатов. Этот параметр &lt;code&gt;page&lt;/code&gt; является необязательным. Если он не включен в URL, мы просто предположим, что номер страницы результатов имеет значение «1».&lt;/p&gt;

&lt;p&gt;Добавьте следующий обработчик под &lt;code&gt;indexHandler&lt;/code&gt; в ваш файл&lt;code&gt;main.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;searchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Internal server error"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;searchKey&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Search Query is: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Results page is: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Приведенный выше код извлекает параметры &lt;code&gt;q&lt;/code&gt; и &lt;code&gt;page&lt;/code&gt; из URL-адреса запроса и выводит их оба в терминал.&lt;/p&gt;

&lt;p&gt;Затем зарегистрируйте функцию &lt;code&gt;searchHandler&lt;/code&gt; в качестве обработчика пути&lt;code&gt;/search&lt;/code&gt;, как показано ниже:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"3000"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/assets/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/assets/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="c"&gt;// Add the next line&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indexHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Не забудьте импортировать пакеты &lt;code&gt;fmt&lt;/code&gt; и&lt;code&gt;net/url&lt;/code&gt; сверху:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"html/template"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"net/url"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Теперь перезапустите сервер, введите запрос в поле поиска и проверьте терминал. Вы должны увидеть ваш запрос в терминале, как показано ниже:&lt;/p&gt;

&lt;h2&gt;
  
  
  Создаём модель данных
&lt;/h2&gt;

&lt;p&gt;Когда мы делаем запрос к конечной точке &lt;a href="https://newsapi.org/docs/endpoints/everything"&gt;News API&lt;code&gt;/everything&lt;/code&gt;&lt;/a&gt;, мы ожидаем ответ json в следующем формате:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4661&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"articles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gizmodo.com"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jennings Brown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"World's Dumbest Bitcoin Scammer Tries to Scam Bitcoin Educator, Gets Scammed in The Process"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ben Perrin is a Canadian cryptocurrency enthusiast and educator who hosts a bitcoin show on YouTube. This is immediately apparent after a quick a look at all his social media. Ten seconds of viewing on of his videos will show that he is knowledgeable about di…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://gizmodo.com/worlds-dumbest-bitcoin-scammer-tries-to-scam-bitcoin-ed-1837032058"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"urlToImage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://i.kinja-img.com/gawker-media/image/upload/s--uLIW_Oxp--/c_fill,fl_progressive,g_center,h_900,q_80,w_1600/s4us4gembzxlsjrkmnbi.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"publishedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2019-08-07T16:30:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ben Perrin is a Canadian cryptocurrency enthusiast and educator who hosts a bitcoin show on YouTube. This is immediately apparent after a quick a look at all his social media. Ten seconds of viewing on of his videos will show that he is knowledgeable about..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Чтобы работать с этими данными в Go, нам нужно сгенерировать структуру, которая отражает данные при декодировании тела ответа. Конечно, вы можете сделать это вручную, но я предпочитаю использовать веб-сайт &lt;a href="https://mholt.github.io/json-to-go/"&gt;JSON-to-Go&lt;/a&gt;, который делает этот процесс действительно простым. Он генерирует структуру Go (с тегами), которая будет работать для этого JSON.&lt;/p&gt;

&lt;p&gt;Все, что вам нужно сделать, это скопировать объект JSON и вставить его в поле, помеченное &lt;strong&gt;JSON&lt;/strong&gt;, затем скопировать вывод и вставить его в свой код. Вот что мы получаем для вышеуказанного объекта JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AutoGenerated&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"status"`&lt;/span&gt;
    &lt;span class="n"&gt;TotalResults&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"totalResults"`&lt;/span&gt;
    &lt;span class="n"&gt;Articles&lt;/span&gt;     &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ID&lt;/span&gt;   &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
            &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;      &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`json:"source"`&lt;/span&gt;
        &lt;span class="n"&gt;Author&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"author"`&lt;/span&gt;
        &lt;span class="n"&gt;Title&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"title"`&lt;/span&gt;
        &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"description"`&lt;/span&gt;
        &lt;span class="n"&gt;URL&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"url"`&lt;/span&gt;
        &lt;span class="n"&gt;URLToImage&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"urlToImage"`&lt;/span&gt;
        &lt;span class="n"&gt;PublishedAt&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt; &lt;span class="s"&gt;`json:"publishedAt"`&lt;/span&gt;
        &lt;span class="n"&gt;Content&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"content"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`json:"articles"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566456278/2019-08-22_07-44.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hGuGejRZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566456278/2019-08-22_07-44.png" alt="Brave browser showing JSON to Go tool"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Я сделал несколько изменений в структуре &lt;code&gt;AutoGenerated&lt;/code&gt;, отделив фрагмент &lt;code&gt;Articles&lt;/code&gt; в его собственную структуру и обновив имя структуры. Вставьте следующее ниже объявление переменной &lt;code&gt;tpl&lt;/code&gt; в &lt;code&gt;main.go&lt;/code&gt; и добавьте пакет &lt;code&gt;time&lt;/code&gt; в ваш импорт:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ID&lt;/span&gt;   &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;      &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Article&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Source&lt;/span&gt;      &lt;span class="n"&gt;Source&lt;/span&gt;    &lt;span class="s"&gt;`json:"source"`&lt;/span&gt;
    &lt;span class="n"&gt;Author&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"author"`&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"title"`&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"description"`&lt;/span&gt;
    &lt;span class="n"&gt;URL&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"url"`&lt;/span&gt;
    &lt;span class="n"&gt;URLToImage&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"urlToImage"`&lt;/span&gt;
    &lt;span class="n"&gt;PublishedAt&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt; &lt;span class="s"&gt;`json:"publishedAt"`&lt;/span&gt;
    &lt;span class="n"&gt;Content&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"content"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"status"`&lt;/span&gt;
    &lt;span class="n"&gt;TotalResults&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;       &lt;span class="s"&gt;`json:"totalResults"`&lt;/span&gt;
    &lt;span class="n"&gt;Articles&lt;/span&gt;     &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Article&lt;/span&gt; &lt;span class="s"&gt;`json:"articles"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Как вы, возможно, знаете, Go требует, чтобы все экспортируемые поля в структуре начинались с заглавной буквы. Однако принято представлять поля JSON с помощью &lt;a href="https://ru.wikipedia.org/wiki/Camel_case"&gt;camelCase&lt;/a&gt; или &lt;a href="https://ru.wikipedia.org/wiki/Snake_case"&gt;snake_case&lt;/a&gt;, которые не начинаются с заглавной буквы.&lt;/p&gt;

&lt;p&gt;Поэтому мы используем теги поля структуры, такие как &lt;code&gt;json:"id"&lt;/code&gt;, чтобы явно отобразить поле структуры в поле JSON, как показано выше. Это также позволяет использовать совершенно разные имена для структурного поля и соответствующего поля json, если это необходимо.&lt;/p&gt;

&lt;p&gt;Наконец, давайте создадим другой тип структуры для каждого поискового запроса. Добавьте это ниже структуры &lt;code&gt;Results&lt;/code&gt; в &lt;code&gt;main.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Search&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;SearchKey&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;NextPage&lt;/span&gt;   &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;TotalPages&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;Results&lt;/span&gt;    &lt;span class="n"&gt;Results&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Эта структура представляет собой каждый поисковый запрос, сделанный пользователем. &lt;code&gt;SearchKey&lt;/code&gt; - это сам запрос, поле &lt;code&gt;NextPage&lt;/code&gt; позволяет пролистывать результаты, &lt;code&gt;TotalPages&lt;/code&gt; - общее количество страниц результатов запроса, а &lt;code&gt;Results&lt;/code&gt; - текущая страница результатов запроса.&lt;/p&gt;

&lt;h2&gt;
  
  
  Отправляем запрос по News API и рендерим результаты
&lt;/h2&gt;

&lt;p&gt;Теперь, когда у нас есть модель данных для нашего приложения, давайте продолжим и сделаем запросы к News API, а затем отрендерим результаты на странице.&lt;/p&gt;

&lt;p&gt;Поскольку для News API требуется ключ API, нам нужно найти способ передать его в нашем приложении без жесткого кодирования в коде. Переменные среды являются распространенным подходом, но я решил использовать вместо них флаги командной строки. Go предоставляет пакет &lt;code&gt;flag&lt;/code&gt;, поддерживающий базовый анализ флагов командной строки, и это то, что мы собираемся использовать здесь.&lt;/p&gt;

&lt;p&gt;Сначала объявите новую переменную &lt;code&gt;apiKey&lt;/code&gt; под переменной &lt;code&gt;tpl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Затем используйте её в функции &lt;code&gt;main&lt;/code&gt; следующим образом:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apikey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Newsapi.org access key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apiKey must be set"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// остальная часть функции&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Здесь мы вызываем метод &lt;code&gt;flag.String()&lt;/code&gt;, который позволяет нам определять строковый флаг. Первый аргумент этого метода - имя флага, второй - значение по умолчанию, а третий - описание использования.&lt;/p&gt;

&lt;p&gt;После определения всех флагов вам нужно вызвать &lt;code&gt;flag.Parse()&lt;/code&gt;, чтобы фактически проанализировать их. Наконец, так как &lt;code&gt;apikey&lt;/code&gt; является обязательным компонентом для этого приложения, мы обеспечиваем аварийное завершение программы, если этот флаг не установлен при выполнении программы.&lt;/p&gt;

&lt;p&gt;Убедитесь, что вы добавили пакет &lt;code&gt;flag&lt;/code&gt; в свой импорт, затем перезапустите сервер и передайте требуемый флаг &lt;code&gt;apikey&lt;/code&gt;, как показано ниже:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go &lt;span class="nt"&gt;-apikey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your newsapi access key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Далее, давайте продолжим и обновим &lt;code&gt;searchHandler&lt;/code&gt;, чтобы поисковый запрос пользователя отправлялся на &lt;a href="http://newsapi.org/"&gt;newsapi.org&lt;/a&gt; и результаты отображались в нашем шаблоне.&lt;/p&gt;

&lt;p&gt;Замените два вызова метода &lt;code&gt;fmt.Println()&lt;/code&gt; в конце функции &lt;code&gt;searchHandler&lt;/code&gt; следующим кодом:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;searchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// beginning  of the function&lt;/span&gt;

    &lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SearchKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;searchKey&lt;/span&gt;

    &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unexpected server error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;
    &lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;

    &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://newsapi.org/v2/everything?q=%s&amp;amp;pageSize=%d&amp;amp;page=%d&amp;amp;apiKey=%s&amp;amp;sortBy=publishedAt&amp;amp;language=en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryEscape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SearchKey&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalPages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalResults&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Сначала мы создаем новый экземпляр структуры &lt;code&gt;Search&lt;/code&gt; и устанавливаем значение поля &lt;code&gt;SearchKey&lt;/code&gt; равным значению параметра URL &lt;code&gt;q&lt;/code&gt; в HTTP-запросе.&lt;/p&gt;

&lt;p&gt;После этого мы конвертируем переменную &lt;code&gt;page&lt;/code&gt; в целое число и присваиваем результат полю &lt;code&gt;NextPage&lt;/code&gt; переменной &lt;code&gt;search&lt;/code&gt;. Затем мы создаем переменную &lt;code&gt;pageSize&lt;/code&gt; и устанавливаем ее значение равным 20. Эта переменная &lt;code&gt;pageSize&lt;/code&gt; представляет количество результатов, которые API новостей будет возвращать в своем ответе. Это значение может находиться в диапазоне от 0 до 100.&lt;/p&gt;

&lt;p&gt;Затем мы создаем конечную точку с помощью &lt;code&gt;fmt.Sprintf()&lt;/code&gt; и делаем запрос GET к ней. Если ответ от News API не &lt;a href="https://freshman.tech/http-status-codes/#200-ok"&gt;200 OK&lt;/a&gt;, мы вернем клиенту общую ошибку сервера. В противном случае тело ответа парсится в &lt;code&gt;search.Results&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Затем мы вычисляем общее количество страниц путем деления поля &lt;code&gt;TotalResults&lt;/code&gt; на &lt;code&gt;pageSize&lt;/code&gt;. Например, если запрос возвращает 100 результатов, а мы одновременно просматриваем только 20, нам нужно будет пролистать пять страниц, чтобы просмотреть все 100 результатов по этому запросу.&lt;/p&gt;

&lt;p&gt;После этого мы рендерим наш шаблон и передаем переменную &lt;code&gt;search&lt;/code&gt; в качестве интерфейса данных. Это позволяет нам получать доступ к данным из объекта JSON в нашем шаблоне, как вы увидите.&lt;/p&gt;

&lt;p&gt;Прежде чем перейти к &lt;code&gt;index.html&lt;/code&gt;, обязательно обновите ваши импорты, как показано ниже:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"flag"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"html/template"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"math"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"net/url"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Давайте продолжим и отобразим результаты на странице, изменив файл &lt;code&gt;index.html&lt;/code&gt; следующим образом. Добавьте это под тегом &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"search-results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ range .Results.Articles }}
      &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"news-article"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"noreferrer noopener"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{.URL}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{.Title }}&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ .Description }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"metadata"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"source"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ .Source.Name }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;time&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"published-date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ .PublishedAt }}&lt;span class="nt"&gt;&amp;lt;/time&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"article-image"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{ .URLToImage }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    {{ end }}
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Чтобы получить доступ к полю структуры в шаблоне, мы используем оператор точки. Этот оператор ссылается на объект структуры (в данном случае &lt;code&gt;search&lt;/code&gt;), а затем внутри шаблона мы просто указываем имя поля (как &lt;code&gt;{{.Results}}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Блок &lt;code&gt;range&lt;/code&gt; позволяет нам перебирать слайс в Go и выводить некоторый HTML для каждого элемента в слайсе. Здесь мы перебираем слайс структур &lt;code&gt;Article&lt;/code&gt;, содержащихся в поле &lt;code&gt;Articles&lt;/code&gt;, и выводим HTML на каждой итерации.&lt;/p&gt;

&lt;p&gt;Перезагрузите сервер, обновите браузер и выполните поиск новостей по популярной теме. Вы должны получить список из 20 результатов на странице, как показано на скрине ниже.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566478651/Screenshot_from_2019-08-22_13-56-33.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2r52EeXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566478651/Screenshot_from_2019-08-22_13-56-33.png" alt="Browser showing news listings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Сохраняем поисковый запрос в инпуте&lt;a href="https://freshman.tech/web-development-with-go/#persist-the-search-query-in-the-input"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Обратите внимание, что поисковый запрос исчезает из ввода, когда страница обновляется с результатами. В идеале запрос должен сохраняться до тех пор, пока пользователь не выполнит новый поиск. Вот как Google Search работает, например.&lt;/p&gt;

&lt;p&gt;Мы можем легко это исправить, обновив атрибут value тега input в нашем файле index.html следующим образом:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;autofocus&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"search-input"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{{ .SearchKey }}"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter a news topic"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Перезапустите браузер и выполните новый поиск. Поисковый запрос будет сохранен, как показано ниже:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566479245/Screenshot_from_2019-08-22_14-06-52.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WYaccP-Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566479245/Screenshot_from_2019-08-22_14-06-52.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Форматируем дату публикации&lt;a href="https://freshman.tech/web-development-with-go/#format-the-published-date"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Если вы посмотрите на дату в каждой статье, вы увидите, что она плохо читаема. Текущий вывод показывает, как News API возвращает дату публикации статьи. Но мы можем легко изменить это, добавив метод в структуру &lt;code&gt;Article&lt;/code&gt; и используя его для форматирования даты вместо использования значения по умолчанию.&lt;/p&gt;

&lt;p&gt;Давайте добавим следующий код чуть ниже структуры &lt;code&gt;Article&lt;/code&gt; в &lt;code&gt;main.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FormatPublishedDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PublishedAt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%v %d, %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Здесь новый метод &lt;code&gt;FormatPublishedDate&lt;/code&gt; создан в структуре &lt;code&gt;Article&lt;/code&gt;, и этот метод форматирует поле &lt;code&gt;PublishedAt&lt;/code&gt; в &lt;code&gt;Article&lt;/code&gt; и возвращает строку в следующем формате: &lt;code&gt;10 января 2009&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Чтобы использовать этот новый метод в вашем шаблоне, замените &lt;code&gt;.PublishedAt&lt;/code&gt; на &lt;code&gt;.FormatPublishedDate&lt;/code&gt; в вашем файле &lt;code&gt;index.html&lt;/code&gt;. Затем перезагрузите сервер и повторите предыдущий поисковый запрос. Это выведет результаты с правильно отформатированным временем, как показано ниже:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566479638/Screenshot_from_2019-08-22_14-13-40.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1r4I6m0n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566479638/Screenshot_from_2019-08-22_14-13-40.png" alt="Brave browser showing correctly formatted date"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Выводим общее количество результатов&lt;a href="https://freshman.tech/web-development-with-go/#show-the-total-number-of-results"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Давайте улучшим пользовательский интерфейс нашего новостного приложения, указав общее количество результатов в верхней части страницы, а затем отобразим сообщение на случай, если по определенному запросу не найдено ни одного результата.&lt;/p&gt;

&lt;p&gt;Все, что вам нужно сделать, это добавить следующий код как дочерний элемент &lt;code&gt;.container&lt;/code&gt;, чуть выше элемента &lt;code&gt;.search-results&lt;/code&gt; в вашем файле &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"result-count"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalResults&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)}}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;About&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;strong&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalResults&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;strong&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="n"&gt;were&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ne&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SearchKey&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalResults&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;strong&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SearchKey&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;strong&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Шаблоны Go поддерживают несколько функций сравнения, некоторые из которых используются выше. Мы используем функцию &lt;code&gt;gt&lt;/code&gt;, чтобы проверить, что поле &lt;code&gt;TotalResults&lt;/code&gt; структуры &lt;code&gt;Results&lt;/code&gt; больше нуля. Если это так, общее количество результатов будет напечатано в верхней части страницы.&lt;/p&gt;

&lt;p&gt;В противном случае, если &lt;code&gt;SearchKey&lt;/code&gt; не равен пустой строке (&lt;code&gt;(ne .SearchKey "")&lt;/code&gt;) и &lt;code&gt;TotalResults&lt;/code&gt; равно нулю (&lt;code&gt;(eq .Results.TotalResults 0)&lt;/code&gt;), то выводится сообщение «No results found».&lt;/p&gt;

&lt;p&gt;Перезапустите сервер и введите несколько слов в поле поиска, чтобы не было найдено новостей по вашему запросу. На экране должно появиться сообщение «No results found».&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566480557/Screenshot_from_2019-08-22_14-29-02.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EUzjf4TT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566480557/Screenshot_from_2019-08-22_14-29-02.png" alt="Browser showing no results found message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;После этого сделайте еще один поисковый запрос на этот раз с популярной темой. Количество результатов будет выведено вверху страницы, как показано ниже:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566480828/Screenshot_from_2019-08-22_14-33-35.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Yyr7h23--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566480828/Screenshot_from_2019-08-22_14-33-35.png" alt="Browser showing results count at the top of the page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Пагинация&lt;a href="https://freshman.tech/web-development-with-go/#pagination"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Так как мы отображаем только 20 результатов одновременно, нам нужен способ, чтобы пользователь мог перейти на следующую или предыдущую страницу результатов в любое время.&lt;/p&gt;

&lt;p&gt;Сначала добавим кнопку ** Next ** внизу результатов, если последняя страница результатов еще не достигнута. Чтобы определить, была ли достигнута последняя страница результатов, создайте этот новый метод ниже объявления структуры &lt;code&gt;Search&lt;/code&gt; в&lt;code&gt;main.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;IsLastPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalPages&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Этот метод проверяет, больше ли поле &lt;code&gt;NextPage&lt;/code&gt;, чем поле &lt;code&gt;TotalPages&lt;/code&gt; в экземпляре &lt;code&gt;Search&lt;/code&gt;. Чтобы это работало, нам нужно увеличивать &lt;code&gt;NextPage&lt;/code&gt; каждый раз, когда отображается новая страница результатов. Вот как это сделать:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;searchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// начало функции&lt;/span&gt;
    &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalPages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalResults&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="c"&gt;// добавьте этот if блок&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsLastPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPage&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// остальная часть функции&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Наконец, давайте добавим кнопку, которая позволит пользователю перейти на следующую страницу результатов. Этот код должен быть помещен ниже &lt;code&gt;.search-results&lt;/code&gt; в вашем файле &lt;code&gt;index.html&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pagination"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {{ if (ne .IsLastPage true) }}
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/search?q={{ .SearchKey }}&amp;amp;page={{ .NextPage }}"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button next-page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  {{ end }}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Пока последняя страница для этого запроса не была достигнута, кнопка &lt;strong&gt;Next&lt;/strong&gt; будет отображаться в нижней части списка результатов.&lt;/p&gt;

&lt;p&gt;Как видите, &lt;code&gt;href&lt;/code&gt; ссылки указывает на маршрут &lt;code&gt;/search&lt;/code&gt; и сохраняет текущий поисковый запрос в параметре &lt;code&gt;q&lt;/code&gt;, используя значение &lt;code&gt;NextPage&lt;/code&gt; в параметре &lt;code&gt;page&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Давайте добавим кнопку &lt;strong&gt;Previous&lt;/strong&gt;. Эту кнопку следует отображать только в том случае, если текущая страница больше 1. Чтобы сделать это, нам нужно создать новый метод &lt;code&gt;CurrentPage()&lt;/code&gt; в &lt;code&gt;Search&lt;/code&gt;, чтобы реализовать это. Добавьте это ниже метода &lt;code&gt;IsLastPage&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;CurrentPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPage&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Текущая страница просто &lt;code&gt;NextPage - 1&lt;/code&gt;, за исключением случаев, когда &lt;code&gt;NextPage&lt;/code&gt; равен 1. Чтобы получить предыдущую страницу, просто вычтите 1 из текущей страницы. Следующий метод делает именно это:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;PreviousPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Таким образом, мы можем добавить следующий код для отображения кнопки &lt;strong&gt;Previous&lt;/strong&gt;, только если текущая страница больше 1. Измените элемент &lt;code&gt;.pagination&lt;/code&gt; в вашем файле &lt;code&gt;index.html&lt;/code&gt; следующим образом:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pagination"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {{ if (gt .NextPage 2) }}
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/search?q={{ .SearchKey }}&amp;amp;page={{ .PreviousPage }}"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button previous-page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Previous&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  {{ end }}
  {{ if (ne .IsLastPage true) }}
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/search?q={{ .SearchKey }}&amp;amp;page={{ .NextPage }}"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button next-page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  {{ end }}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Теперь перезагрузите сервер и сделайте новый поисковый запрос. У вас должно получиться пролистать результаты, как показано ниже:&lt;/p&gt;

&lt;h2&gt;
  
  
  Показываем текущую страницу&lt;a href="https://freshman.tech/web-development-with-go/#show-the-current-page"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Вместо того, чтобы отображать только общее количество результатов, найденных для запроса, пользователю также полезно просмотреть общее количество страниц для этого запроса и страницу, на которой он в данный момент находится.&lt;/p&gt;

&lt;p&gt;Для этого нам нужно всего лишь изменить наш файл &lt;code&gt;index.html&lt;/code&gt; следующим образом:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"result-count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {{ if (gt .Results.TotalResults 0)}}
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;About &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;{{ .Results.TotalResults }}&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; results were found. You are on page &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;{{ .CurrentPage }}&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; of &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt; {{ .TotalPages }}&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  {{ else if (ne .SearchKey "") and (eq .Results.TotalResults 0) }}
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;No results found for your query: &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;{{ .SearchKey }}&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  {{ end }}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;После того, как вы перезапустите сервер и выполните новый поиск, в верхней части страницы будет указана текущая страница и общее количество страниц вместе с общим количеством результатов.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566482694/Screenshot_from_2019-08-22_15-04-27.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DTxO7SlL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566482694/Screenshot_from_2019-08-22_15-04-27.png" alt="Browser showing current page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Деплоим на Heroku&lt;a href="https://freshman.tech/web-development-with-go/#deploy-to-heroku"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Теперь, когда наше приложение полнофункционально, давайте продолжим и развернем его в Heroku. &lt;a href="https://signup.heroku.com/"&gt;Зарегистрируйте бесплатную учетную запись&lt;/a&gt;, затем перейдите по этой ссылке, чтобы создать новое приложение. Укажите для приложения уникальное имя. Я назвал приложение &lt;strong&gt;freshman-news&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Затем &lt;a href="https://devcenter.heroku.com/articles/heroku-command-line"&gt;следуйте инструкциям здесь&lt;/a&gt;, чтобы установить интерфейс командной строки Heroku на свой компьютер. Затем выполните команду &lt;code&gt;heroku login&lt;/code&gt; в терминале, чтобы войти в свою учетную запись Heroku.&lt;/p&gt;

&lt;p&gt;Убедитесь, что вы инициализировали git-репозиторий для своего проекта. Если нет, запустите команду &lt;code&gt;git init&lt;/code&gt; в корне каталога вашего проекта, а затем выполните команду ниже, чтобы установить heroku в качестве удаленного git-репозитория. Замените &lt;code&gt;freshman-news&lt;/code&gt; названием вашего приложения.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;heroku git:remote &lt;span class="nt"&gt;-a&lt;/span&gt; freshman-news
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Затем создайте Procfile в корневом каталоге вашего проекта (&lt;code&gt;touch Procfile&lt;/code&gt;) и вставьте следующее содержимое:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;web: bin/news-demo &lt;span class="nt"&gt;-apikey&lt;/span&gt; &lt;span class="nv"&gt;$NEWS_API_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;После этого укажите репозиторий GitHub для своего проекта и версию Go, которую вы используете, в своем файле &lt;code&gt;go.mod&lt;/code&gt;, как показано ниже. Создайте этот файл, если он еще не существует, в корне проекта.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;freshman&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tech&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;news&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="m"&gt;1.12.9&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Перед развертыванием приложения перейдите на вкладку &lt;strong&gt;Settings&lt;/strong&gt; на панели инструментов Heroku и нажмите &lt;strong&gt;Reveal Config Vars&lt;/strong&gt;. Нам нужно установить переменную среды &lt;strong&gt;NEWS_API_KEY&lt;/strong&gt;, чтобы она могла быть передана в бинарный файл при запуске сервера.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/freshman/image/upload/v1566487319/2019-08-22_16-21.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--riHER6w8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/freshman/image/upload/v1566487319/2019-08-22_16-21.png" alt="Heroku config variables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Наконец, сделайте коммит своего кода и сделайте пуш в Heroku с помощью следующих команд:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;
git push heroku master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;После завершения процесса деплоя вы можете открыть https://название&lt;em&gt;вашего&lt;/em&gt;приложения.herokuapp.com, чтобы просмотреть и протестировать свой проект.&lt;/p&gt;

&lt;h2&gt;
  
  
  Заключение&lt;a href="https://freshman.tech/web-development-with-go/#wrap-up"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;В этой статье мы успешно создали приложение News и обучились основам использования Go для веб-разработки. Мы также изучили, как развернуть готовое приложение в Heroku. &lt;/p&gt;

&lt;p&gt;Я надеюсь, что эта статья была полезна для вас. Если у вас есть какие-либо вопросы относительно этого туториала, оставьте комментарий ниже, и я перезвоню вам. &lt;/p&gt;

&lt;p&gt;Спасибо за чтение!&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>news</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Рефакторьте свой унаследованный PHP код (примеры из реальных проектов)</title>
      <dc:creator>Petrovichev Sergey</dc:creator>
      <pubDate>Thu, 26 Sep 2019 12:20:08 +0000</pubDate>
      <link>https://forem.com/petrovichevsergey/php-2b48</link>
      <guid>https://forem.com/petrovichevsergey/php-2b48</guid>
      <description>&lt;p&gt;перевод статьи автора Mohamed Aladdin на &lt;a href="%5Bhttps://medium.com/hackernoon/refactor-your-php-legacy-code-real-projects-examples-da9edf03ff4b%5D(https://medium.com/hackernoon/refactor-your-php-legacy-code-real-projects-examples-da9edf03ff4b)"&gt;Medium&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://miro.medium.com/max/60/1*5U_fhmDrqC3hZ_1SIj0QmA.png?q=20"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WM-zHehO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/503/1%2A5U_fhmDrqC3hZ_1SIj0QmA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WM-zHehO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/503/1%2A5U_fhmDrqC3hZ_1SIj0QmA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;image from osnews.com&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Хорошие разработчики определяются качеством их кода. В индустрии программного обеспечения написание хорошего кода означает экономию средств, которые могут быть вложены в тестирование, обновление, расширение или исправление ошибок. В этой статье я покажу вам реальные примеры некоторых техник и идей, которые помогут вам очистить ваш унаследованный код и реорганизовать его, чтобы сделать его более надежным и модульным. Эти методы не только помогут вам реорганизовать ваш старый код, но и дадут вам отличные идеи о том, как теперь писать чистый код.&lt;/p&gt;

&lt;h1&gt;
  
  
  Что такое рефакторинг и зачем он нам?
&lt;/h1&gt;

&lt;p&gt;Рефакторинг относится к методам и шагам, которые помогут вам написать чистый код. Это важно для других разработчиков, которые смогут читать, расширять и повторно использовать код без необходимости много редактировать его.&lt;/p&gt;

&lt;p&gt;Ниже я покажу вам несколько примеров рефакторинга унаследованного кода и сделаю его лучше.&lt;/p&gt;

&lt;h1&gt;
  
  
  Никогда не рефакторьте продакшн код, который не имеет unit тестов
&lt;/h1&gt;

&lt;p&gt;Мой первый совет - никогда не начинать рефакторинг унаследованного кода, который не имеет надлежащих unit тестов. Я предполагаю, что причина очевидна: у вас останутся сломанные функции, которые сложно исправить, потому что вы не сможете понять, что сломано. Поэтому, если вам нужно реорганизовать его, начните сначала с его тестирования. Убедитесь, что часть, которую вы собираетесь перерабатывать, покрыта тестами.&lt;br&gt;
Проверьте  &lt;a href="https://phpunit.readthedocs.io/en/7.1/code-coverage-analysis.html"&gt;PHPUnit анализ покрытия кода тестами&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Начните рефакторинг с самой глубокой точки вашего кода
&lt;/h1&gt;

&lt;p&gt;Посмотрите на следующее изображение. Это настоящий проект для системы управления &lt;a href="https://hackernoon.com/tagged/management"&gt;гостиницей&lt;/a&gt;  которую я нашел на Github. Это настоящий проект с открытым исходным кодом, поэтому закрытый источник может быть худшим.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fCZyfRdo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2Ao_Xt7O_1WitOzJx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fCZyfRdo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2Ao_Xt7O_1WitOzJx9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;пример: сначала рефакторинг самых глубоких точек&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Как вы можете видеть в этом методе, есть три уровня, отмеченные красным. Самой глубокой точкой должна быть вложенная инструкция if / else внутри первого условия if. Обычно самая глубокая точка сфокусирована на одной логике, тем самым облегчая рефакторинг.&lt;/p&gt;

&lt;h1&gt;
  
  
  Сократите ваши методы, разделив их на более мелкие методы или файлы конфигурации / таблицу БД.
&lt;/h1&gt;

&lt;p&gt;Возможно, в этом случае мы можем извлечь его в приватный метод следующим образом:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QerwfPAF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2AGzntaUY08VZDx_mD.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QerwfPAF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2AGzntaUY08VZDx_mD.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;сделайте свои функции короче&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Следующей глубокой точкой будет выборка данных поста и загрузка просмотров. Теперь взгляните на метод add () после рефакторинга других частей. Это намного чище, лучше читается и тестируемо.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cXbDsSji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2A5rTlqNl6knjMKdBk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cXbDsSji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2A5rTlqNl6knjMKdBk.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;пример: сначала рефакторинг самых глубоких точек&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Всегда используйте {} в операторах if
&lt;/h1&gt;

&lt;p&gt;Большинство &lt;a href="https://hackernoon.com/tagged/programming"&gt;языков&lt;/a&gt; программирования поддерживают однострочные операторы if, и некоторые разработчики используют их, потому что они просты, однако не так просто читаются и легко вызывают проблемы, поскольку только одна пустая строка может нарушить условие и начать сбой. Посмотрите на разницу между двумя примерами:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kyi7Hg5D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/300/0%2AqKPPZhC6bI0tcHy8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kyi7Hg5D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/300/0%2AqKPPZhC6bI0tcHy8.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;пример: используйте фигурные скобки&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Не используйте магические числа или магические строки:
&lt;/h1&gt;

&lt;p&gt;В следующем примере вы заметите, что если комнат больше 250, возвращается сообщение об ошибке. В этом случае 250 считается магическим числом. Если вы не разработчик, который написал это, вам будет сложно понять, что это за число.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wKI4qDQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/300/0%2Aof8kepNKAX3zsRp5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wKI4qDQc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/300/0%2Aof8kepNKAX3zsRp5.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;пример: магические числа&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Чтобы реорганизовать этот метод, мы можем выяснить, что 250 - это максимальное количество комнат. Поэтому вместо хардкода мы можем извлечь его в переменную $maxAvailableRooms. Теперь код стал более понятен для других разработчиков.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EpJPeFsg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/300/0%2A5nR9rHxduxPvfUZJ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EpJPeFsg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/300/0%2A5nR9rHxduxPvfUZJ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;пример: исправление магических чисел&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Не используйте операторы else, если это вам не требуется:
&lt;/h1&gt;

&lt;p&gt;В той же функции availablerooms () вы заметили оператор if, в котором мы можем легко избавиться от остальной части, и логика останется прежней.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ISQPiDwK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/300/0%2AEL3AvdzpKT9uibeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ISQPiDwK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/300/0%2AEL3AvdzpKT9uibeo.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;пример: игнорирование оператора else&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Используйте значимые имена для ваших методов, переменных и тестов
&lt;/h1&gt;

&lt;p&gt;В следующем примере вы можете видеть, что есть два метода из системы управления отелем, называемые «index() и room_m()». Лично я не могу определить, каковы их цели. Я думаю, что было бы легче понять, если бы их имена были описательными.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TkBs5gEj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2Ar1mxi52OtJ5RXw-m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TkBs5gEj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2Ar1mxi52OtJ5RXw-m.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;пример: неправильные имена методов&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Используйте максимум возможностей вашего языка программирования
&lt;/h1&gt;

&lt;p&gt;Многие разработчики не используют все возможности языка программирования, на котором они пишут. Многие из этих возможностей могут сэкономить вам уйму усилий и сделать ваш код более надежным. Посмотрите на следующие примеры и обратите внимание, как легко достичь того же результата с меньшим количеством кода, просто используя подсказку типа.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_UUhxSys--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2AqBo2t1VxVGDLd5gZ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_UUhxSys--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2AqBo2t1VxVGDLd5gZ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Na1duYHL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2AlI9BoaA39baxGFY6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Na1duYHL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1024/0%2AlI9BoaA39baxGFY6.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Я хотел бы закончить несколькими более короткими советами для лучшего написания кода:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Используйте новую форму массива [] вместо старой (array).&lt;/li&gt;
&lt;li&gt;  Используйте оператор === вместо ==, если нужно проверить тип данных.&lt;/li&gt;
&lt;li&gt;  Всегда полезно давать публичным методам короткие описательные имена. Частные методы могут иметь более длинные имена, поскольку они имеют ограниченную область действия.&lt;/li&gt;
&lt;li&gt;  Используйте общие имена только с методами, которые реализуют интерфейсы, например add (), и используйте описательные имена для методов отдельных классов addUser () или addDocument ().&lt;/li&gt;
&lt;li&gt;  Удаляйте неиспользуемые методы из ваших классов.&lt;/li&gt;
&lt;li&gt;  Используйте префикс is / has с функциями, которые возвращают логическое значение например: isAdmin(\$user), hasPermission(\$user).&lt;/li&gt;
&lt;li&gt;  Всегда используйте модификаторы доступа в методах и свойствах класса.&lt;/li&gt;
&lt;li&gt;  Будьте осторожны, не захламляйте интерфейсы: используйте только те методы, которые пользователи могут использовать публично.&lt;/li&gt;
&lt;li&gt;  Организовывайте так методы классов, чтобы публичные методы находились сверху.&lt;/li&gt;
&lt;li&gt;  Всегда применяйте концепцию единой ответственности к вашим классам.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>refactorit</category>
      <category>legacy</category>
    </item>
  </channel>
</rss>
