Go в примери: Образци за словоплет

Го предлага вградена поддръжка за създаване на променливо1 съдържание или за показване на пригодѐн за потребителя изход с пакета text/template. Сродният му пакет html/template предоставя същото взаимодействие2 но има добавени пособия за сигурност и е предназначен за извеждане на HTML3.


  1. dynamic – променливо
  2. (API) application programming interface – обявено от програмиста взаимодействие за ползване на набор от обекти – в най-общ смисъл
  3. HTML – Hypertext Markup Language – език за обозначаване на свръхтекст
package main
import (
    "os"
    "text/template"
)
func main() {

Можем да създадем нов образец1 и да разберем2 тялото му от низ. Образците са смесица от словен плет (текст) и „действия“, обгърнати в две двойки къдрави скоби – {{...}}, които са предназначени да вмъкнат променливо съдържание.


  1. template – образец на документ с места за попълване, обозначени по някакъв начин
  2. parse – правя разбор – разбирам; разделям на по-малки парчета, за да събера наново, но произвеждайки качествено ново нещо.
    t1 := template.New("t1")
    t1, err := t1.Parse("Стойността е {{.}}\n")
    if err != nil {
        panic(err)
    }

Можем също да използваме функцията template.Must, за да ужасим програмата, в случай че Parse върне грешка. Това е особено полезно при образци, наченати1 в общия обхват2 на програмата - общодостъпни.


  1. initialized – наченат, инициализиран
  2. global scope – общ обхват (на програма), там където дадена променлива може да бъде достъпена от всяка част на програмата
    t1 = template.Must(t1.Parse("Стойността е: {{.}}\n"))

Като „изпълним“ образеца, пресъздаваме словоплета му със зададените за всяко действие стойности. Действието {{.}} – точка между двойни къдрави скоби – бива заместено с подадената на Execute (изпълнявам) стойност.

    t1.Execute(os.Stdout, "нѣкакъв словен плѣт")
    t1.Execute(os.Stdout, 5)
    t1.Execute(os.Stdout, []string{
        "Go",
        "Rust",
        "C++",
        "C#",
    })

Помощна функция, която ще ползваме по-долу.

    Create := func(name, t string) *template.Template {
        return template.Must(template.New(name).Parse(t))
    }

Ако данната е структура, можем да ползваме действието {{.ИмеНаПоле}} за достъп до полетата ѝ. Полетата трябва да са изнесени1, за да са достъпни, когато образецът бива изпълнен.


  1. exported – изнесен (навън), видим, достъпен, общодостъпен. Всяко поле, започващо с главна буква е изнесено. В други езици, public – общодостъпно.
    t2 := Create("t2", "Име: {{.Име}}\n")
    t2.Execute(os.Stdout, struct {
        Име string
    }{"Янка Готованка"})

Същото се отнася за карти. При картите имената на ключовете могат да започват и с малки букви.

    t2.Execute(os.Stdout, map[string]string{
        "Име": "Педя Човек",
    })

Изявленията if/else, предоставят условно изпълнение в образците. Една стойност се смята за false ако е нулева стойност за съответния вид данни. Например 0, празен низ, нулев указател и т.н. Това парче показва друга способност на образците: употребата на действия - за окастряне на бели пространства.

    t3 := Create("t3",
        "{{if . -}} да {{- else -}} не {{- end}}\n")
    t3.Execute(os.Stdout, "непразно")
    t3.Execute(os.Stdout, "")

Блоковете range ни дават възможност за повторителни действия върху всеки член от отрязъци, поредици, карти или канали. Вътре в блока {{.}} съдържа текущата стойност в повторението.

    t4 := Create("t4",
        "Обход: {{range .}}{{.}} {{end}}\n")
    t4.Execute(os.Stdout,
        []string{
            "Go",
            "Rust",
            "C++",
            "C#",
        })
}
$ go run templates.go 
Стойността е: нѣкакъв словен плѣт
Стойността е: 5
Стойността е: [Go Rust C++ C#]
Име: Янка Готованка
Име: Педя Човек
да
не
Обход: Go Rust C++ C#

Следващ пример: .