‹Title› Повышение уровня с нуля до `+ hero +` ‹/title›

Go стал одним из самых популярных языков общего программирования в современной технологической экосистеме. Одна из причин, по которой Go является моим любимым языком, заключается в том, что он побуждает разработчика «думать как программист». Несмотря на то, что количество фантастических библиотек и пакетов растет, Go достаточно модульный, поэтому часто проще (если не лучше) создавать свои собственные программные решения, используя только стандартную библиотеку, а не полагаться на третьих лиц * кашляет, Python, кашляет * .

Это особенно заметно с помощью шаблонов, которые позволяют настраивать вывод динамически, но структурированно. Шаблоны можно использовать для отображения информации на веб-странице или для рассылки электронных писем клиентской базе. В этом уроке мы рассмотрим шаблоны в следующих разделах:

  • Основы шаблонов в Go
  • Передача составных структур данных в шаблоны
  • Передача функций в шаблоны

Шаблоны чрезвычайно полезны, когда дело доходит до веб-разработки на Go, так что приступим!

Основы шаблонов в Go

Шаблоны позволяют нам динамически отображать выходные данные. Скажем, например, мы хотим вставить переменную в тело HTML, мы можем сделать это с помощью шаблонов. Используя обратные тики, мы можем вставить переменные first и last в теги <h1></h1> в фрагменте кода ниже.

Тогда запуск программы даст нам…

$ go build
$ ./main
        <!doctype html>
        <html lang="en">
        <head>
        <meta charset="utf-8">
        </head>
        <body>
        <h1>Izzy Miles thinks Go is awesome!</h1>
        </body>
        </html>
    
$

Но это может только нас завести. Что, если у нас есть много шаблонов, которые нужно обрабатывать на лету? Неужели нам действительно нужно реализовывать логику, чтобы разбирать все самостоятельно? Вот тут-то и пригодится стандартная библиотека Go - давайте взглянем на нее.

Шаблоны с текстом / пакетом шаблонов

Допустим, у нас есть несколько шаблонов, к которым мы хотим получить динамический доступ. Используя пакет text/template, мы можем эффективно анализировать файлы как шаблоны. Здесь нам нужно сделать два шага. Первый - проанализировать файл для получения ссылки на один или несколько шаблонов.

Затем мы можем вызывать методы этих шаблонов, такие как ExecuteTemplate, который принимает в качестве параметров писателя, имя файла и объект данных. ExecuteTemplate затем применит данный шаблон к объекту данных и затем запишет вывод в объект записи. Давайте посмотрим на пример.

Сначала давайте создадим несколько новых файлов для работы, включая наш main.go и несколько файлов в качестве шаблонов.

Примечание. Файлы шаблонов могут иметь любое имя и любое расширение. Вам решать, ссылаться на них прямо в коде, но по стандарту расширение должно быть .gohtml.

$ touch main.go one.gohtml two.gohtml three.gohtml

Затем вы можете заполнить файлы шаблонов чем угодно. Теперь перейдем к коду.

Опять же, первый шаг, который нам нужно сделать, - это проанализировать шаблон (ы). Мы делаем это с помощью template.ParseFiles(), который берет относительные пути ко всем файлам, которые мы хотим проанализировать. После проверки наличия ошибки мы можем затем вызвать ExecuteTemplate, который принимает писатель, имя шаблона и объект данных для записи. У нас нет данных, поэтому мы можем просто сослаться на "one.gohtml" из объекта templateRef, который содержит ссылки на наши проанализированные шаблоны.

Чтобы продолжить, мы также можем использовать некоторые изящные UNIX-подобные методы, такие как ParseGlob, которые будут анализировать любые шаблоны, соответствующие определенному шаблону. В этом случае любой шаблон с расширением .gohtml будет проанализирован и сохранен в объекте templateRef. Затем мы можем вызвать ExecuteTemplate для проанализированных шаблонов, показанных выше.

Если бы мы запустили эту программу, мы бы получили ...

$ go run *.go
FIRST TEMPLATE
SECOND TEMPLATE
THIRD TEMPLATE

Передача данных в шаблон

В наши шаблоны легко передавать любые данные. После синтаксического анализа мы можем просто заполнить поле данных любым отдельным фрагментом данных. Таким образом, вы можете передать int, строку или, как мы увидим, даже пользовательские типы данных!

Все, что нам нужно сделать, это указать тип данных в нашем вызове ExecuteTemplate(), а также указать в самом шаблоне, куда данные должны идти. Мой шаблон one.gohtml выглядит так:

FIRST TEMPLATE {{.}}

Где символ {{.}} будет ссылаться на текущее состояние объекта данных. Итак, если вы отправляете биты фрагмента, вы получите текущую версию фрагмента для каждого вызова.

Соответствующий код Go выглядит следующим образом:

Наконец, если мы запустим эту программу, мы получим следующее:

$ go run *.go
FIRST TEMPLATE received a string object

Вы даже можете назначить переданные данные переменной в вашем шаблоне:

{{$myVar := .}}FIRST TEMPLATE {{$myVar}}

Примечание. Для эффективности важно, чтобы вы анализировали шаблоны только один раз, поэтому было бы неплохо написать вспомогательный метод, который сначала проанализирует список нужных файлов, прежде чем выполнять какие-либо дальнейшие действия.

Вы можете узнать больше о пакете text/template здесь:



Передача составных структур данных в шаблоны

Замечательно, что теперь мы можем передавать простые объекты данных в наши шаблоны, но это пока только нас. Мы также можем передавать структуры данных, такие как массивы, карты и структуры, в наши шаблоны, что обеспечивает более точный и функциональный окончательный вывод. Давайте посмотрим на несколько примеров.

Передача массивов в шаблоны

В этой программе мы просто определяем массив строк с именем wizards. Затем мы делаем первый шаг - анализируем файл шаблона, чтобы получить ссылку на указатель templateRef. Наконец, мы вызываем ExecuteTemplate для ссылки, одновременно передавая массив wizards в качестве объекта данных.

Чтобы отобразить переданные данные в нашем шаблоне, мы должны указать структуру вывода данных. В шаблоне файла wizards.gohtml у меня есть следующий код, который действует как неупорядоченный список HTML. Мы можем начать цикл по переданному объекту данных ., используя ключевое слово range, которое требует размещения end для закрытия цикла. Затем мы можем получить доступ к отдельным элементам массива, снова обратившись к . из внутри цикла range.

<body>
    <ul>
        {{range .}}
        <li>{{.}}</li>
        {{end}}
    </ul>
</body>

Если бы мы запустили приведенный выше фрагмент кода Go с шаблоном wizards.gohtml, мы бы получили следующий результат:

$ go run *.go
<body>
    <ul>
        
        <li>Harry Potter</li>
        
        <li>Hermione Granger</li>
        
        <li>Ron Weasley</li>
        
    </ul>
</body>

Передача карт в шаблоны

Пакет text/templates Go сохраняет для нас удобство и согласованность. Мы можем определить карту под названием wizards с именем мастера в качестве ключа и сердцевиной его палочки в качестве значения. Мы повторяем наши предыдущие шаги и передаем карту вызову метода ExecuteTemplate.

Затем мы можем получить доступ к парам ключ-значение в шаблоне для окончательного вывода. Мы делаем это, снова используя ключевое слово range в текущем объекте данных ., которое дает нам пары в виде переменных, которые мы затем отображаем.

<body>
    <ul>
        {{range $key, $value := .}}
        <li>{{$key}} has a wand made of {{$value}}</li>
        {{end}}
    </ul>
</body>

При запуске указанной выше программы будет выведено…

$ go run *.go
<body>
    <ul>
        
        <li>Harry Potter has a wand made of Phoenix feather</li>
        
        <li>Hermione Granger has a wand made of Dragon heartstring</li>
        
        <li>Ron Weasley has a wand made of Unicorn hair</li>
        
    </ul>
</body>

Передача структур в шаблоны

Одно из моих любимых свойств Go - простота его настраиваемой структуры типов. Здесь мы определяем структуру с именем wizard с двумя свойствами Name и WandCore. Затем мы создаем экземпляр нового wizard с именем hp, который, как и раньше, передаем в ссылку на наш шаблон.

На мой взгляд, пользовательские структуры проще всего форматировать в шаблонах. Все, что вам нужно сделать, это указать свойство структуры, которое вы хотите отобразить, и код станет более читабельным!

<body>
    <ul>
        <li>{{.Name}} has a wand made of {{.WandCore}}</li>
    </ul>
</body>

Запуск программы дает ожидаемый результат.

$ go run *.go
<body>
    <ul>
        <li>Harry Potter has a wand made of Phoenix feather</li>
    </ul>
</body>

Вы можете использовать шаблоны в Go для обработки любой конкретной ситуации, в которой вы находитесь, используя ключевое слово range для перебора любых списков объектов и специальный символ . для ссылки на текущее состояние отдельного объекта данных. Таким образом, вы можете перебрать список структур, чтобы отобразить их свойства или любую другую комбинацию, которая придет в голову!

Передача функций в шаблоны

Подводя итог, можно также передать функции нашим шаблонам. Зачем нам это нужно? Ну, во-первых, вы НЕ хотите выполнять какую-либо обработку данных из ваших шаблонов, которая приведет к сильно связанному коду. Вместо этого после обработки данных в основной логике кода Go вы можете вызывать функции в шаблонах, чтобы помочь отображать данные с большей степенью сложности.

Чтобы передать функции нашим шаблонам, в пакете text/templates есть метод с именем Funcs(), который требует типа данных с именем FuncMap, который содержит карту строк для функций. Мы определяем наш собственный template.FuncMap{}, называемый templateFuncMap, который имеет две функции "upperCase" и "double", которые мы определяем в строке 11.

Затем в строке 22 мы объединяем несколько методов, которые стоит разобраться. Сначала мы должны определить новый шаблон с template.New(""), чтобы передать наш templateFuncMap вызову метода Funcs(). Когда у нас есть наш новый шаблон с включенными функциями, затем мы можем вызвать ParseFiles() для соответствующего шаблона. Если мы попытаемся вызвать template.ParseFiles() сразу, то столкнемся с проблемой курицы и яйца, когда не сможем получить шаблон с определенными пользовательскими функциями.

Получив ссылку на наш новый шаблон, мы можем теперь вызывать наши пользовательские функции из нашего шаблона:

<body>
    <ul>
        <li>{{upperCase .Name}}'s wand is {{double .WandCore}}</li>
    </ul>
</body>

Выполнение приведенного выше кода, наконец, даст нам ...

$ go run *.go
<body>
    <ul>
        <li>HARRY POTTER has a wand made of Phoenix featherPhoenix feather</li>
    </ul>
</body>

С помощью настраиваемых функций вы можете добавить еще более динамическое поведение для отображения ваших данных, как настоящий веб-разработчик Go.

Надеюсь, вам понравилось читать это руководство и вы смогли изучить возможности использования шаблонов для динамического отображения данных в Go. Если были какие-то непонятные темы или по которым вы хотели бы написать новую статью, оставьте комментарий ниже! Спасибо за прочтение.