суббота, 27 июля 2019 г.

ООП в Golang: public vs. private (публичный против частного)

Пакет - это самая маленькая единица частной инкапсуляции в Go.

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

Экспортируемые и неэкспортированные идентификаторы используются для описания открытого интерфейса пакета и для защиты от определенных ошибок программирования.

Предупреждение. Неэкспортированные идентификаторы не являются мерой безопасности и не скрывают и не защищают какую-либо информацию.

Пример. В следующем пакете единственными экспортируемыми идентификаторами являются StopWatch и Start.

package timer

import "time"

// StopWatch - это простая утилита часов.
// Его нулевое значение - это бездействующие часы с общим временем 0.
type StopWatch struct {
    start   time.Time
    total   time.Duration
    running bool
}

// Start включает часы.
func (s *StopWatch) Start() {
    if !s.running {
        s.start = time.Now()
        s.running = true
    }
}

StopWatch и его экспортируемые методы могут быть импортированы и использованы в другом пакете.

package main

import "timer"

func main() {
    clock := new(timer.StopWatch)
    clock.Start()
    if clock.running { // Недопустимо
        // …
    }
}

../main.go:8:15: clock.running undefined (cannot refer to unexported field or method clock.running)


Читайте также:


пятница, 26 июля 2019 г.

Пакет Gorilla mux

В этом посте представлена подборка статей о пакете Gorilla mux, используемом для маршрутизации веб-запросов.

  1. Пакет Gorilla mux для обработки веб-запросов
  2. Пакет Gorilla mux: маршруты, субмаршруты
  3. Пакет Gorilla mux: построение зарегистрированных URL
  4. Пакет Gorilla mux: добавление промежуточного программного обеспечения (middleware)

ООП в Golang: методы не для классов, но для типов

В Go нет классов, но вы можете определять методы для типов.

Вы можете определить методы для любого типа, объявленного в определении типа.

Метод - это функция с дополнительным аргументом получателя. Получатель находится между ключевым словом func и именем метода. В следующем примере метод HasGarage связан с типом House. Получатель метода назван p.

type House struct {
    garage bool
}

func (p *House) HasGarage() bool { return p.garage }

func main() {
    house := new(House)
    fmt.Println(house.HasGarage()) // Печатает "false" (нулевое значение)
}

Преобразования и методы

Если вы преобразуете значение в другой тип, новое значение будет иметь методы нового типа, но не старого.

type MyInt int

func (m MyInt) Positive() bool { return m > 0 }

func main() {
    var m MyInt = 2
    m = m * m // Операторы базового типа все еще применяются.

    fmt.Println(m.Positive())        // Печатает "true"
    fmt.Println(MyInt(3).Positive()) // Печатает "true"

    var n int
    n = int(m) // Требуется преобразование.
    n = m      // Недопустимо
}

../main.go:14:4: cannot use m (type MyInt) as type int in assignment

В Go идиоматично преобразовывать тип выражения для доступа к определенному методу.

var n int64 = 12345
fmt.Println(n)                // 12345
fmt.Println(time.Duration(n)) // 12.345µs

(Основной тип time.Duration - int64, а тип time.Duration имеет метод String, который возвращает продолжительность, отформатированную как время.)


Читайте также:


четверг, 25 июля 2019 г.

Объектно-ориентированное программирование с наследованием в Golang

Наследование в традиционных объектно-ориентированных языках предлагает три функции в одном. Когда Cat наследуется от Animal:

  • класс Cat повторно использует код из класса Animal,
  • переменная x типа Animal может ссылаться либо к Cat, либо к Animal,
  • x.Eat() выберет метод Eat в зависимости от того, к какому типу относится объект x.

В объектно-ориентированном жаргоне эти функции известны как повторное использование кода (code reuse), полиморфизм и динамическая диспетчеризация (dynamic dispatch).

Все они доступны в Go, используя отдельные конструкции:

  • композиция (composition) и встраивание (embedding) обеспечивают повторное использование кода,
  • интерфейсы заботятся о полиморфизме и динамической диспетчеризации.

Повторное использование кода посредством композиции (composition)

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

Если Cat требуются некоторые или все функциональные возможности Animal, просто используйте композицию (composition).

type Animal struct {
    // …
}

type Cat struct {
    fluffy Animal
    // …
}

Это дает вам полную свободу использования Animal части вашей Cat по мере необходимости.

Повторное использование кода посредством встраивания (embedding)

Если класс Cat наследует точное поведение Animal, такой подход может привести к утомительному написанию повторяющегося кода.

type Animal struct {
    // …
}

func (a *Animal) Eat()   { … }
func (a *Animal) Sleep() { … }
func (a *Animal) Walk() { … }

type Cat struct {
    fluffy Animal
    // …
}

func (a *Cat) Eat()   { a.fluffy.Eat() }
func (a *Cat) Sleep() { a.fluffy.Sleep() }
func (a *Cat) Walk()  { a.fluffy.Walk() }

Этот шаблон написания кода известен как делегирование.

Go использует встраивание для подобных ситуаций. Объявление структуры Cat и ее трех методов можно сократить до:

type Cat struct {
    Animal
    // …
}

Полиморфизм и динамическая диспетчеризация с интерфейсами

Держите свои интерфейсы короткими и вводите их только при необходимости.

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

Если вам нужно усыпить всех своих питомцев, вы можете определить интерфейс Sleeper.

type Sleeper interface {
    Sleep()
}

func main() {
    pets := []Sleeper{new(Cat), new(Dog)}
    for _, x := range pets {
        x.Sleep()
    }
}

Никакого явного объявления не требуется для типов Cat и Dog. Любой тип, который предоставляет методы, названные в интерфейсе, может рассматриваться как реализация.


Читайте также:


Пакет Gorilla mux: добавление промежуточного программного обеспечения (middleware)

Mux поддерживает добавление промежуточного программного обеспечения (middleware) к маршрутизатору (Router), который выполняется в порядке их добавления, если найдено совпадение, включая его подчиненные маршрутизаторы. Промежуточное программное обеспечение - это (как правило) небольшие куски кода, которые принимают один запрос, что-то с ним делают и передают другому промежуточному программному обеспечению или конечному обработчику. Некоторыми распространенными вариантами использования промежуточного программного обеспечения являются ведение журнала запросов, манипулирование заголовками или перехват ResponseWriter.

type MiddlewareFunc func(http.Handler) http.Handler

Как правило, возвращаемый обработчик является замыканием, которое делает что-то с переданными ему http.ResponseWriter и http.Request, а затем вызывает обработчик, переданный в качестве параметра в MiddlewareFunc (замыкания могут обращаться к переменным из контекста, в котором они созданы).

Простое базовое промежуточное программное обеспечение, которое регистрирует URI обрабатываемого запроса, может быть записано как:

func simpleMw(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Делаем работу здесь
        log.Println(r.RequestURI)
        // Вызов следующего обработчика, 
        // который может быть другим промежуточным программным 
        // обеспечением в цепочке или конечным обработчиком.
        next.ServeHTTP(w, r)
    })
}

Промежуточное программное обеспечение (middleware) может быть добавлено к маршрутизатору с помощью Router.Use():

r := mux.NewRouter()
r.HandleFunc("/", handler)
r.Use(simpleMw)

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

// Определим нашу структуру
type authenticationMiddleware struct {
    tokenUsers map[string]string
}

// Инициализируем где-нибудь
func (amw *authenticationMiddleware) Populate() {
    amw.tokenUsers["00000000"] = "user0"
    amw.tokenUsers["aaaaaaaa"] = "userA"
    amw.tokenUsers["05f717e5"] = "randomUser"
    amw.tokenUsers["deadbeef"] = "user0"
}

// Функция промежуточного программного обеспечения, 
// которая будет вызываться для каждого запроса
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("X-Session-Token")

        if user, found := amw.tokenUsers[token]; found {
            // Мы нашли токен в нашей карте
            log.Printf("Authenticated user %s\n", user)
            next.ServeHTTP(w, r)
        } else {
            http.Error(w, "Forbidden", http.StatusForbidden)
        }
    })
}

r := mux.NewRouter()
r.HandleFunc("/", handler)

amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
amw.Populate()

r.Use(amw.Middleware)

Примечание. Цепочка обработчиков будет остановлена, если ваше промежуточное программное обеспечение не вызовет next.ServeHTTP() с соответствующими параметрами. Это можно использовать для отмены запроса, если этого хочет автор промежуточного программного обеспечения.

Пример использования middleware с Gorilla mux:

package mux_test

import (
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

// Определим нашу структуру
type authenticationMiddleware struct {
    tokenUsers map[string]string
}
// Инициализируем где-нибудь
func (amw *authenticationMiddleware) Populate() {
    amw.tokenUsers["00000000"] = "user0"
    amw.tokenUsers["aaaaaaaa"] = "userA"
    amw.tokenUsers["05f717e5"] = "randomUser"
    amw.tokenUsers["deadbeef"] = "user0"
}

// Функция промежуточного программного обеспечения, которая будет вызываться для каждого запроса
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("X-Session-Token")

        if user, found := amw.tokenUsers[token]; found {
            // Мы нашли токен в нашей карте
            log.Printf("Authenticated user %s\n", user)
            next.ServeHTTP(w, r)
        } else {
            http.Error(w, "Forbidden", http.StatusForbidden)
        }
    })
}

func Example_authenticationMiddleware() {
    r := mux.NewRouter()
    r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // Делаем что-то здесь
    })
    amw := authenticationMiddleware{make(map[string]string)}
    amw.Populate()
    r.Use(amw.Middleware)
}


Читайте также:


Пакет Gorilla mux: построение зарегистрированных URL

В этом посте рассмотрим, как построить зарегистрированные URL с пакетом Gorilla mux.

Маршруты могут быть названы. Все маршруты, которые определяют имя, могут иметь свои построенные URL-адреса. Мы определяем имя, вызывая Name() на маршруте. Например:

r := mux.NewRouter()
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
  Name("article")

Чтобы построить URL, получите маршрут и вызовите метод URL(), передав последовательность пар ключ/значение для переменных маршрута. Для предыдущего маршрута мы бы сделали:

url, err := r.Get("article").URL("category", "technology", "id", "42")

... и результатом будет url.URL со следующим путем:

"/articles/technology/42"

Это также работает для переменных значения хоста и запроса:

r := mux.NewRouter()
r.Host("{subdomain}.domain.com").
  Path("/articles/{category}/{id:[0-9]+}").
  Queries("filter", "{filter}").
  HandlerFunc(ArticleHandler).
  Name("article")

// url.String() будет "http://news.domain.com/articles/technology/42?filter=gorilla"
url, err := r.Get("article").URL("subdomain", "news",
                                 "category", "technology",
                                 "id", "42",
                                 "filter", "gorilla")

Все переменные, определенные в маршруте, являются обязательными, и их значения должны соответствовать соответствующим шаблонам. Эти требования гарантируют, что сгенерированный URL всегда будет соответствовать зарегистрированному маршруту - единственное исключение - явно определенные маршруты "только для сборки" ("build-only"), которые никогда не совпадают.

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

r.HeadersRegexp("Content-Type", "application/(text|json)")

... и маршрут будет соответствовать обоим запросам с Content-Type `application/json`, а также `application/text`

Существует также способ построения только хоста или пути URL для маршрута: для этого используйте методы URLHost() или URLPath(). Для предыдущего маршрута мы бы сделали:

// "http://news.domain.com/"
host, err := r.Get("article").URLHost("subdomain", "news")

// "/articles/technology/42"
path, err := r.Get("article").URLPath("category", "technology", "id", "42")

И если вы используете подчиненные маршрутизаторы (subrouters), хост и путь, определенные отдельно, также могут быть построены:

r := mux.NewRouter()
s := r.Host("{subdomain}.domain.com").Subrouter()
s.Path("/articles/{category}/{id:[0-9]+}").
  HandlerFunc(ArticleHandler).
  Name("article")

// "http://news.domain.com/articles/technology/42"
url, err := r.Get("article").URL("subdomain", "news",
                                 "category", "technology",
                                 "id", "42")


Читайте также:


вторник, 23 июля 2019 г.

Пакет Gorilla mux: маршруты, субмаршруты

Маршруты также могут быть ограничены доменом или поддоменом. Просто определите шаблон хоста для сопоставления. Они также могут иметь переменные:

r := mux.NewRouter()
// Соответствует только если домен "www.example.com".
r.Host("www.example.com")
// Соответствует динамическому поддомену.
r.Host("{subdomain:[a-z]+}.domain.com")

Есть несколько других совпадений, которые можно добавить. Чтобы соответствовать префиксам пути:

r.PathPrefix("/products/")

... или методам HTTP:

r.Methods("GET", "POST")

... или схеме URL:

r.Schemes("https")

... или значению заголовка:

r.Headers("X-Requested-With", "XMLHttpRequest")

... или значению запроса:

r.Queries("key", "value")

... или использовать пользовательскую функцию соответствия:

r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
    return r.ProtoMajor == 0
})

... и, наконец, можно объединить несколько сопоставителей в одном маршруте:

r.HandleFunc("/products", ProductsHandler).
  Host("www.example.com").
  Methods("GET").
  Schemes("http")

Задавать одни и те же условия сопоставления снова и снова может быть скучно, поэтому есть способ сгруппировать несколько маршрутов с одинаковыми требованиями. Он называется "субмаршрутизацией" (subrouting).

Например, допустим, есть несколько URL-адресов, которые должны совпадать только в том случае, если хостом является "www.example.com". Создайте маршрут для этого хоста и получите от него "субмаршрутизатор" ("subrouter"):

r := mux.NewRouter()
s := r.Host("www.example.com").Subrouter()

Затем зарегистрируйте маршруты в субмаршрутизаторе(subrouter):

s.HandleFunc("/products/", ProductsHandler)
s.HandleFunc("/products/{key}", ProductHandler)
s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)

Три URL-пути, которые мы зарегистрировали выше, будут проверяться только в том случае, если домен является "www.example.com", поскольку сначала проверяется подчиненный маршрутизатор (subrouter). Это не только удобно, но и оптимизирует сопоставление запросов. Вы можете создавать субмаршрутизаторы (subrouters), комбинирующие любые сопоставления атрибутов, принятые маршрутом (route).

Субмаршрутизаторы (Subrouters) могут использоваться для создания "пространств имен" ("namespaces") домена или пути: вы определяете субмаршрутизаторы в одном месте, а затем части приложения могут регистрировать свои пути относительно данного субмаршрутизатора.

Есть еще одна вещь о субмаршрутах (subroutes). Когда у подчиненного маршрутизатора (subrouter) есть префикс пути, внутренние маршруты используют его в качестве основы для своих путей:

r := mux.NewRouter()
s := r.PathPrefix("/products").Subrouter()

// "/products/"
s.HandleFunc("/", ProductsHandler)

// "/products/{key}/"
s.HandleFunc("/{key}/", ProductHandler)

// "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler)

Обратите внимание, что путь к PathPrefix() представляет собой "подстановочный знак" ("wildcard"): вызов PathPrefix("/static/").Handler(...) означает, что обработчику будет передан любой запрос, соответствующий "/static/*". Это позволяет легко обслуживать статические файлы с помощью mux:

func main() {
    var dir string

    flag.StringVar(&dir, "dir", ".", "каталог для обслуживания файлов. По умолчанию текущий каталог")
    flag.Parse()
    r := mux.NewRouter()

    // Это будет обслуживать файлы по адресу 
    // http://localhost:8000/static/
    r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))

    srv := &http.Server{
        Handler:      r,
        Addr:         "127.0.0.1:8000",
        // Хорошая практика: 
        // применять таймауты для серверов, 
        // которые вы создаете!
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }

    log.Fatal(srv.ListenAndServe())
}


Читайте также:


понедельник, 22 июля 2019 г.

Пакет Gorilla mux для обработки веб-запросов

Gorilla это набор инструментов для веб-программирования (web toolkit).

Пакет Gorilla mux реализует маршрутизатор запросов (request router) и диспетчер.

Установка

$ go get github.com/gorilla/mux

Импорт

import "github.com/gorilla/mux"

Использование

Название mux означает "мультиплексор HTTP-запросов". Как и стандартный http.ServeMux, mux.Router сопоставляет входящие запросы со списком зарегистрированных маршрутов и вызывает обработчик для маршрута, который соответствует URL-адресу или другим условиям. Основными функциями являются:

1. Запросы могут быть сопоставлены на основе URL хоста, пути, префикса пути, схем, значения заголовка и запроса, метода HTTP или использование пользовательских сопоставлений.

2. У URL хостов, путей и значений запроса могут быть переменные с необязательным регулярным выражением.

3. Зарегистрированные URL-адреса могут быть построены или "перевернуты", что помогает поддерживать ссылки на ресурсы.

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

5. Реализует интерфейс http.Handler, поэтому совместим со стандартным http.ServeMux.

Зарегистрируем пару URL-путей и обработчиков:

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", HomeHandler)
    r.HandleFunc("/products", ProductsHandler)
    r.HandleFunc("/articles", ArticlesHandler)
    http.Handle("/", r)
}

Здесь мы регистрируем три маршрута, отображающие URL-пути к обработчикам. Это эквивалентно тому, как работает http.HandleFunc(): если URL входящего запроса совпадает с одним из путей, соответствующий обработчик называется передачей (http.ResponseWriter, *http.Request) в качестве параметров.

Пути могут иметь переменные. Они определяются в формате {имя} или {имя:шаблон}. Если шаблон регулярного выражения не определен, соответствующая переменная будет иметь значение до следующей косой черты. Например:

r := mux.NewRouter()
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)

Группы могут использоваться внутри шаблонов, если они не фиксируются (?:re). Например:

r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)

Имена используются для создания карты переменных маршрута, которые можно получить с помощью mux.Vars():

vars := mux.Vars(request)
category := vars["category"]

Обратите внимание, что если присутствуют какие-либо группы захвата, mux будет вызывать panic() во время анализа. Чтобы предотвратить это, преобразуйте любые группы захвата в не-захваты, например, замените "/{sort:(asc|desc)}" на "/{sort:(?:asc|desc)}". Это отличие от предыдущих версий, которые вели себя непредсказуемо, когда присутствовали группы захвата.


Читайте также:


воскресенье, 21 июля 2019 г.

Команды в Golang

В этом посте представлена подборка статей описывающих использование команд Go либо справочные статьи, выдаваемые командами Go.

  1. Команды Go: введение
  2. Инструмент go, команды
  3. Команды go: go build, компиляция пакетов и зависимостей
  4. Команды go: go clean, удаление объектных файлов и кэшированных файлов
  5. Команды go: go doc, показать документацию для пакета или символа
  6. Команды go: go env, напечатать информацию о среде окружения Go
  7. Команды go: go fix, обновить пакеты, чтобы использовать новые API
  8. Команды go: go fmt, gofmt (переформатировать) источники (исходные файлы) пакетов
  9. Команды go: go generate, генерация Go файлов посредством обработки источника
  10. Команды go: go get, загрузка и установка пакетов и зависимостей
  11. Команды go: go install, компиляция и установка пакетов и зависимостей
  12. Команды go: go list, вывод списка пакетов или модулей
  13. Команды go: go mod, обслуживание модуля
  14. Команды go: go mod download, загрузка модулей в локальный кеш
  15. Команды go: go mod edit, редактирование go.mod из инструментов или скриптов
  16. Команды go: go mod graph, распечатать граф требований модуля
  17. Команды go: go mod init, инициализировать новый модуль в текущем каталоге
  18. Команды go: go mod tidy, добавить отсутствующие и удалить неиспользуемые модули
  19. Команды go: go mod vendor, сделать вендорную копию зависимостей
  20. Команды go: go mod verify, проверка достоверности зависимостей
  21. Команды go: go mod why, объяснение необходимости пакета или модуля
  22. Команды go: go run, скомпилировать и запустить Go программу
  23. Команды go: go test, тестировать пакеты
  24. Команды go: go tool, запустить указанный инструмент go
  25. Команды go: go version, напечатать версию Go
  26. Команды go: go vet, сообщить о возможных ошибках в пакетах
  27. Вспомогательные темы инструмента go: режимы сборки
  28. Вспомогательные темы инструмента go: вызовы между Go и C
  29. Вспомогательные темы инструмента go: кеширование сборки и тестирования
  30. Вспомогательные темы инструмента go: переменные среды окружения
  31. Вспомогательные темы инструмента go: типы файлов
  32. Вспомогательные темы инструмента go: файл go.mod
  33. Вспомогательные темы инструмента go: переменная среды GOPATH
  34. Установка переменной среды GOPATH
  35. GOPATH и модули в Golang, внутренние каталоги
  36. Каталоги поставщиков (Vendor Directories) в Golang
  37. Вспомогательные темы инструмента go: протокол прокси модуля
  38. Вспомогательные темы инструмента go: пути импорта
  39. Пути удаленного импорта в Golang
  40. Проверка пути импорта в Golang
  41. Вспомогательные темы инструмента go: модули
  42. Определение модуля, файл go.mod
  43. Основной модуль и список сборки в Golang
  44. Поддержка требований модуля в Golang
  45. Псевдо-версии модулей в Golang
  46. Запросы модулей (module query) в Golang
  47. Совместимость модулей и семантическое управление версиями в Golang
  48. Загрузка и проверка модуля в Golang
  49. Модули и вендоринг в Golang
  50. Команда go get в режиме с поддержкой модулей
  51. Списки пакетов и шаблоны в Golang
  52. Флаги тестирования в Golang
  53. Функции тестирования в Golang
  54. Команда cover в Golang
  55. Команда cgo, использование cgo с командой go
  56. Команда cgo: ссылки Go к C
  57. Команда cgo: ссылки C к Go
  58. Команда cgo: передача указателей
  59. Команда cgo: особые случаи
  60. Использование команды cgo напрямую
  61. Команда fix в Golang
  62. Команда gofmt в Golang
  63. Команда vet в Golang
  64. Команда godoc в Golang


пятница, 19 июля 2019 г.

Команда godoc в Golang

godoc извлекает и генерирует документацию для программ Go.

Он работает как веб-сервер и представляет документацию как веб-страницу.

godoc -http=:6060

Использование:

godoc [flag]

Флаги:

-v
    режим с подробным выводом

-timestamps=true
    показать временные метки (timestamps) 
    со списком каталогов

-index
    включить идентификатор и индекс 
    полнотекстового поиска (окно поиска не отображается, 
    если -index не установлен)

-index_files=""
    шаблон glob с указанием индексных файлов; 
    если не пустой, индекс читается из этих файлов 
    в отсортированном порядке

-index_throttle=0.75
    значение указателя дроссельной заслонки; 
    значение 0 означает, что время не выделяется
    для индексатора (индексатор никогда не завершится), 
    значение 1,0 означает, что создание индекса 
    выполняется с полной скоростью (другим goroutines 
    может не хватить времени, пока индекс строится)

-index_interval=0
    интервал индексации; значение 0 устанавливает 5 минут,
    отрицательные значения индексов - 
    только один раз при запуске

-play=false
    включить песочницу

-links=true
    связать идентификаторы с их объявлениями

-write_index=false
    записать индекс в файл; 
    имя файла должно быть указано с
    -index_files

-maxresults=10000
    показано максимальное количество результатов 
    полнотекстового поиска (полнотекстовый индекс 
    не создается, если maxresults <= 0)

-notes="BUG"
    маркеры соответствия регулярного выражения, 
    чтобы показать (например, "BUG|TODO", ".*")

-goroot=$GOROOT
    Go корневой каталог

-http=addr
    адрес HTTP сервиса 
    (например, '127.0.0.1:6060' или просто ':6060')

-analysis=type,pointer
    разделенный запятыми список анализов для выполнения
    "type": отображать разрешение идентификатора, 
            информацию о типе, наборы методов,
            'implements' и статические вызываемые
    "pointer": отображать одноранговые каналы, 
               вызывающие и динамические абоненты канала
               (значительно медленнее)

-templates=""
    каталог, содержащий альтернативные файлы шаблонов;
    если установлено, каталог может содержать 
    альтернативные файлы шаблонов
    для файлов в $GOROOT/lib/godoc

-url=path
    вывести на стандартный вывод данные, 
    которые будут выдаваться
    HTTP запросом для указанного пути (path)

-zip=""
    zip-файл, предоставляющий файловую систему 
    для обслуживания; отключено, если пусто

По умолчанию godoc просматривает пакеты, которые находит через $GOROOT и $GOPATH (если установлены). Это поведение можно изменить, указав альтернативный $GOROOT с флагом -goroot.

Когда установлен флаг -index, индекс поиска сохраняется. Индекс создается при запуске.

Индекс содержит информацию как по идентификатору, так и по полнотекстовому поиску (поиск по регулярным выражениям) Максимальное количество отображаемых результатов полнотекстового поиска можно установить с помощью флага -maxresults; если установлено значение 0, полнотекстовые результаты не отображаются, и создается только индекс идентификатора, но не создается индекс полнотекстового поиска.

По умолчанию godoc использует системные GOOS/GOARCH. Вы можете указать параметры URL "GOOS" и "GOARCH", чтобы настроить вывод на веб-странице целевой системы.

Режим представления веб-страниц, обслуживаемых godoc, можно контролировать с помощью URL параметра "m"; в качестве значения он принимает список имен флагов через запятую:

all     показывать документацию для всех объявлений, 
        а не только экспортируемых

methods показывать все встроенные методы, а не только те, 
        которые не были экспортированы анонимными полями

src     показывать исходный код, 
        а не извлеченную документацию

flat    представить плоский (без отступа) 
        список каталогов с использованием полных путей

Например, https://golang.org/pkg/math/big/?m=all показывает документацию для всех (не только экспортируемых) объявлений пакета big.

По умолчанию godoc обслуживает файлы из файловой системы базовой ОС. Вместо этого .zip-файл может быть предоставлен с помощью флага -zip, который содержит файловую систему для обслуживания. Пути к файлам, хранящиеся в .zip-файле, должны использовать косую черту ('/') в качестве разделителя пути; и они должны быть без корней. Для $GOROOT (или -goroot) должен быть указан путь к каталогу файла .zip, содержащий корневой каталог Go. Например, для файла .zip, созданного командой:

zip -r go.zip $HOME/go

можно запустить godoc следующим образом:

godoc -http=:6060 -zip=go.zip -goroot=$HOME/go

Документация godoc конвертируется в HTML или в текст с использованием пакета go/doc. Godoc также показывает пример кода, который запускается пакетом тестирования


Читайте также:


четверг, 18 июля 2019 г.

Команда vet в Golang

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

Vet обычно вызывается с помощью команды go. Эта команда проверяет пакет в текущем каталоге:

go vet

тогда как следующий пример проверяет пакеты, путь которых указан:

go vet my/project/...

Используйте go help packages, чтобы увидеть другие способы указания, какие пакеты проверять.

Код выхода vet не равен нулю для ошибочного вызова инструмента или, если возникла проблема, и 0 в противном случае. Обратите внимание, что инструмент проверяет не все возможные проблемы и зависит от ненадежной эвристики, поэтому его следует использовать только в качестве руководства, а не в качестве надежного индикатора правильности программы.

Чтобы просмотреть список доступных проверок, запустите "go tool vet help":

asmdecl      сообщить несоответствия между сборочными 
             файлами (assembly files) и Go декларациями

assign       проверить на бесполезные назначения

atomic       проверить на общие ошибки 
             используемые в sync/atomic пакете

bools        проверить на общие ошибки 
             затрагивающие булевы (boolean) операторы

buildtag     проверить что +build теги 
             правильно сформированы и корректно размещены

cgocall      выявить некоторые из нарушений 
             правил передачи cgo указателей

composites   проверить на композитные литералы без ключей 
             (unkeyed composite literals)

copylocks    проверить на locks 
             ошибочно переданные по значению

httpresponse проверить на ошибки использования HTTP ответов

loopclosure  проверить запросы на прохождение циклом 
             по переменным из вложенных функций

lostcancel   проверить cancel функции 
             возвращенные context.WithCancel при вызове

nilfunc      проверить на бесполезные сравнения 
             между функциями и nil

printf       проверить соответствие 
             строк и аргументов формата Printf

shift        проверить на сдвиги которые равны 
             или превосходят ширину целых чисел

stdmethods   проверить сигнатуры методов 
             хорошо известных интерфейсов

structtag    проверить что теги полей структур 
             соответствуют reflect.StructTag.Get

tests        проверить на общие ошибочные 
             использования тестов и примеров

unmarshal    сообщить о передаче unmarshal значений 
             не-указателей или не-интерфейсов 

unreachable  проверить на наличие недостижимого кода

unsafeptr    проверить на невалидные преобразования 
             uintptr в unsafe.Pointer

unusedresult проверить на неиспользуемые результаты 
             вызовов некоторых функций

Для получения подробной информации и флагов конкретной проверки, например printf, запустите "go tool vet help printf".

По умолчанию все проверки выполняются. Если для каких-либо флагов явно задано значение true, запускаются только эти тесты. И наоборот, если какой-либо флаг явно установлен в false, только эти тесты отключаются. Таким образом -printf=true запускает проверку printf, а -printf=false запускает все проверки, кроме проверки printf.

Основные флаги:

-c=N
    отображать проблемные строки 
    плюс N строк окружающего контекста
-json
    выводить аналитическую диагностику 
    (и ошибки) в формате JSON


Читайте также:


Команда gofmt в Golang

gofmt форматирует программы Go. Используются табы для отступа и пробелы для выравнивания. Выравнивание предполагает, что редактор использует шрифт фиксированной ширины.

Без явного пути обрабатывает стандартный ввод. При указании файла работает с этим файлом; при указании каталога рекурсивно работает со всеми файлами .go в этом каталоге. (Файлы, начинающиеся с точки, игнорируются.) По умолчанию gofmt печатает переформатированные источники на стандартный вывод.

Использование:

gofmt [flags] [path ...]

Флаги:

-d
    Не печатать отформатированные источники 
    на стандартный вывод.
    Если форматирование файла отличается от gofmt, 
    вывести diff на стандартный вывод.
-e
    Распечатать все (включая ложные) ошибки.
-l
    Не печатать отформатированные источники 
    на стандартный вывод.
    Если форматирование файла отличается от формата gofmt, 
    вывести его имя на стандартный вывод.
-r rule
    Применить правило (rule) перезаписи 
    к источнику перед переформатированием.
-s
    Попробовать упростить код 
    (после применения правила перезаписи, если оно есть).
-w
    Не печатать отформатированные источники 
    на стандартный вывод.
    Если форматирование файла отличается от формата gofmt, 
    перезаписать его версией gofmt. 
    Если во время перезаписи произошла ошибка,
    исходный файл восстанавливается 
    из автоматического резервного копирования.

Поддержка отладки:

-cpuprofile filename
    Записать профиль процессора в указанный файл.

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

pattern -> replacement

Шаблон (pattern) и замена (replacement) должны быть валидными выражениями Go. В шаблоне односимвольные строчные идентификаторы служат подстановочными знаками, соответствующими произвольным подвыражениям; эти выражения будут заменены теми же идентификаторами при замене.

Когда gofmt читает из стандартного ввода, он принимает либо полную программу Go, либо фрагмент программы. Фрагмент программы должен быть синтаксически допустимым списком объявлений, списком утверждений или выражением. При форматировании такого фрагмента gofmt сохраняет начальные отступы, а также начальные и конечные пробелы, так что отдельные разделы программы Go могут быть отформатированы путем передачи их через gofmt.

Примеры использования gofmt

Чтобы проверить файлы на наличие ненужных скобок:

gofmt -r '(a) -> a' -l *.go

Чтобы удалить скобки:

gofmt -r '(a) -> a' -w *.go

Чтобы преобразовать дерево пакетов из явных верхних границ среза в неявные:

gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src

Команда simplify (упростить)

При вызове с -s gofmt по возможности сделает следующие исходные преобразования.

Составной литерал массива, среза или карты в форме:
    []T{T{}, T{}}
будет упрощено до:
    []T{{}, {}}

Выражение среза формы:
    s[a:len(s)]
будет упрощено до:
    s[a:]

Диапазон (range) формы:
    for x, _ = range v {...}
будет упрощено до:
    for x = range v {...}

Диапазон (range) формы:
    for _ = range v {...}
будет упрощено до:
    for range v {...}

Это может привести к изменениям, которые несовместимы с более ранними версиями Go.


Читайте также:


среда, 17 июля 2019 г.

Команда fix в Golang

fix находит программы Go, использующие старые API, и переписывает их для использования более новых. После обновления до новой версии Go fix помогает внести необходимые изменения в ваших программах.

Использование:

go tool fix [-r name,...] [path ...]

Без явного пути fix читает стандартный ввод и записывает результат в стандартный вывод.

Если именованный путь является файлом, fix перезаписывает именованные файлы на месте. Если именованный путь является каталогом, fix переписывает все файлы .go в этом дереве каталогов. Когда fix перезаписывает файл, он печатает строку со стандартной ошибкой, в которой указаны имя файла и примененная перезапись.

Если установлен флаг -diff, файлы не перезаписываются. Взамен fix печатает различия, которые внесет переписывание.

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

Fix выводит полный список исправлений, которые он может применить в своем выводе справки; чтобы увидеть их, запустите go tool fix -help.

Fix не делает резервные копии файлов, которые он редактирует. Вместо этого используйте функциональность “diff” системы контроля версий для проверки изменений, которые вносит fix, перед тем как выполнить коммит.


Читайте также:


понедельник, 15 июля 2019 г.

Использование команды cgo напрямую

Использование:

go tool cgo [cgo options] [-- compiler options] gofiles...

Cgo преобразует указанные исходные Go файлы ввода в несколько исходных Go и C файлов вывода.

Параметры компилятора пропускаются неинтерпретированными при вызове компилятора C для компиляции частей C пакета.

Следующие параметры доступны при запуске cgo напрямую:

-V
    Распечатать версию cgo и выйти.
-debug-define
    Опция отладки. Печатает #defines.
-debug-gcc
    Опция отладки. 
    Отслеживает исполнение и вывод C компилятора.
-dynimport file
    Написать список символов, импортируемых файлом. 
    Написать в аргумент -dynout или стандартный вывод. 
    Используется командой go build при создании пакета cgo.
-dynlinker
    Написать динамический компоновщик (linker) 
    как часть вывода -dynimport.
-dynout file
    Записать -dynimport вывод в файл.
-dynpackage package
    Задать Go пакет для -dynimport вывода.
-exportheader file
    Если есть какие-либо экспортируемые функции, записать
    сгенерированные декларации экспорта в файл.
    Код C может производить #include этого, 
    чтобы увидеть объявления.
-importpath string
    Путь импорта для Go пакета. Необязательный; 
    используется для создания более читаемых комментариев 
    в сгенерированных файлах.
-import_runtime_cgo
    Если установлен (по умолчанию), 
    импортировать runtime/cgo в сгенерированный вывод.
-import_syscall
    Если установлен (по умолчанию), 
    импортировать syscall в сгенерированный вывод.
-gccgo
    Генерировать вывод для компилятора gccgo, а не для
    компилятора gc.
-gccgoprefix prefix
    Опция -fgo-prefix для использования с gccgo.
-gccgopkgpath path
    Опция -fgo-pkgpath для использования с gccgo.
-godefs
    Перезаписать входной файл в Go синтаксис, 
    заменяя имена пакетов C реальными значениями. 
    Используется для генерации файлов в пакете syscall 
    при начальной загрузке новой цели.
-objdir directory
    Поместите все созданные файлы в указанный каталог.
-srcdir directory
    Каталог исходных файлов.


Читайте также:


Команда cgo: особые случаи

Несколько специальных типов C, которые обычно представлены типом указателя в Go, вместо этого представлены uintptr. К ним относятся:

1. Типы *Ref для Darwin, основанные на типе CFTypeRef CoreFoundation.

2. Типы объектов из интерфейса JNI Java:

jobject
jclass
jthrowable
jstring
jarray
jbooleanArray
jbyteArray
jcharArray
jshortArray
jintArray
jlongArray
jfloatArray
jdoubleArray
jobjectArray
jweak

3. Тип EGLDisplay из API EGL.

Эти типы являются uintptr на стороне Go, потому что в противном случае они могли бы сбить с толку сборщик мусора Go; иногда это не указатели, а структуры данных, закодированные в виде указателя. Все операции над этими типами должны происходить в C. Подходящая константа для инициализации пустой такой ссылки - 0, а не nil.

Эти особые случаи были введены в Go 1.10. Для автоматического обновления кода из Go 1.9 и более ранних версий используйте cftype или jni перезаписи в инструменте go fix:

go tool fix -r cftype 
go tool fix -r jni 

Он заменит nil на 0 в соответствующих местах.

Случай EGLDisplay был представлен в Go 1.12. Используйте перезапись egl для автоматического обновления кода с Go 1.11 и более ранних версий:

go tool fix -r egl 


Читайте также:


Команда cgo: передача указателей

Go - это язык со сборщиком мусора, и сборщик мусора должен знать расположение каждого указателя на память Go. Из-за этого существуют ограничения на передачу указателей между Go и C.

В этом посте термин указатель Go означает указатель на память, выделенную Go (например, с помощью оператора & или вызвав предопределенную функцию new), а термин C указатель означает указатель на память, выделенную C (например, путем вызова C.malloc). Является ли указатель указателем Go или указателем C, в любом случае это динамическое свойство, определяемое тем, как была выделена память; это не имеет ничего общего с типом указателя.

Обратите внимание, что значения некоторых типов Go, кроме нулевого значения типа, всегда включают указатели Go. Это верно для типов строки, среза, интерфейса, канала, карты и функций. Тип указателя может содержать указатель Go или указатель C. Типы массивов и структур могут включать или не включать указатели Go в зависимости от типов элементов. Все обсуждения ниже по поводу указателей Go применяются не только к типам указателей, но и к другим типам, которые включают указатели Go.

Код Go может передавать указатель Go в C, если память Go, на которую он указывает, не содержит указателей Go. Код C должен сохранять это свойство: он не должен хранить указатели Go в памяти Go, даже временно. При передаче указателя на поле в структуре рассматриваемая память Go - это память, занятая полем, а не вся структура. При передаче указателя на элемент в массиве или срезе рассматриваемая память Go представляет собой весь массив или весь базовый массив среза.

Код C может не сохранять копию указателя Go после возврата вызова. Это включает в себя тип _GoString_, который, как отмечено выше, включает в себя указатель Go; Значения _GoString_ не могут быть сохранены кодом C.

Функция Go, вызываемая кодом C, может не возвращать указатель Go (что означает, что она не может возвращать строку, срез, канал и т.д.). Функция Go, вызываемая кодом C, может принимать указатели C в качестве аргументов, и она может хранить данные не указателя или данные указателя C через эти указатели, но она не может хранить указатель Go в памяти, на которую указывает указатель C. Функция Go, вызываемая кодом C, может принимать указатель Go в качестве аргумента, но она должна сохранять свойство, что память Go, на которую указывает указатель, не содержит указателей Go.

Код Go не может хранить указатель Go в памяти C. Код C может хранить указатели Go в памяти C, в соответствии с приведенным выше правилом: он должен прекратить хранить указатель Go, когда функция C вернется.

Эти правила проверяются динамически во время выполнения. Проверка контролируется параметром cgocheck переменной среды GODEBUG. Значением по умолчанию является GODEBUG=cgocheck=1, которое реализует достаточно дешевые динамические проверки. Эти проверки могут быть полностью отключены с помощью GODEBUG=cgocheck=0. Полная проверка обработки указателя, за определенную плату во время выполнения, доступна через GODEBUG=cgocheck=2.

Можно победить это применение с помощью unsafe пакета, и, конечно, ничто не мешает коду C делать все, что ему нравится. Однако программы, нарушающие эти правила, могут потерпеть неудачу неожидаемым и непредсказуемым образом.

Примечание: текущая реализация имеет ошибку. В то время как коду Go разрешено записывать ноль или указатель C (но не указатель Go) в память C, текущая реализация может иногда вызывать ошибку времени выполнения, если содержимое памяти C выглядит как указатель Go. Поэтому избегайте передачи неинициализированной памяти C в код Go, если код Go будет хранить в ней значения указателя. Обнулите память в C, прежде чем передать ее в Go.


Читайте также:


Команда cgo: ссылки C к Go

Функции Go могут быть экспортированы для использования кодом C следующим образом:

//export MyFunction
func MyFunction(arg1, arg2 int, arg3 string) int64 {...}

//export MyFunction2
func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}

Они будут доступны в коде C как:

extern int64 MyFunction(int arg1, int arg2, GoString arg3);
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);

находятся в сгенерированном заголовке _cgo_export.h после копирования всех преамбул из входных файлов cgo. Функции с несколькими возвращаемыми значениями отображаются на функции, возвращающие структуру.

Не все типы Go могут быть сопоставлены с типами C полезным способом. Типы структур (struct) Go не поддерживаются; используйте тип структуры С. Типы массивов Go не поддерживаются; используйте указатель C.

Функции Go, которые принимают аргументы типа string, могут вызываться с типом C _GoString_, описанным в предыдущем посте. Тип _GoString_ будет автоматически определен в преамбуле. Обратите внимание, что в коде C нет способа создать значение этого типа; это полезно только для передачи строковых значений из Go в C и обратно в Go.

Использование //export в файле накладывает ограничение на преамбулу: поскольку он копируется в два разных выходных файла C, он не должен содержать никаких определений (definitions), только объявления (declarations). Если файл содержит определения и объявления, тогда два выходных файла будут производить дубликаты символов, и компоновщик потерпит неудачу. Чтобы избежать этого, определения должны быть помещены в преамбулы в другие файлы или в исходные файлы на языке C.


Читайте также:


воскресенье, 14 июля 2019 г.

Команда cgo: ссылки Go к C

В файле Go к именам структурных полей C, которые являются ключевыми словами в Go, можно получить доступ, поставив перед ними префикс подчеркивания: если x указывает на структуру C с полем с именем "type", x._type получает доступ к полю. Поля структуры C, которые не могут быть выражены в Go, такие как битовые поля или неправильно выровненные данные, опускаются в структуре Go и заменяются соответствующим заполнением для достижения следующего поля или конца структуры.

Стандартные числовые типы C доступны под именами C.char, C.schar (char со знаком), C.uchar (char без знака), C.short, C.ushort (short без знака), C.int, C.uint (int без знака), C.long, C.ulong (long без знака), C.longlong (long long), C.ulonglong (long long без знака), C.float, C.double, C.complexfloat (complex float) и C.complexdouble (complex double). Тип C void* представлен небезопасным Go-указателем. Типы C __int128_t и __uint128_t представлены типом [16]byte.

Несколько специальных типов C, которые обычно представлены типом указателя в Go, вместо этого представлены uintptr.

Чтобы получить прямой доступ к типу struct, union или enum, поставьте перед ним префикс struct_, union_ или enum_, как в C.struct_stat.

Размер любого типа C доступен как C.sizeof_T, как и в C.sizeof_struct_stat.

Функция C может быть объявлена в файле Go с типом параметра со специальным именем _GoString_. Эта функция может вызываться с обычным значением строки Go. Длина строки и указатель на содержимое строки могут быть доступны путем вызова функций C

size_t _GoStringLen(_GoString_ s);
const char *_GoStringPtr(_GoString_ s);

Эти функции доступны только в преамбуле, но не в других файлах C. Код C не должен изменять содержимое указателя, возвращаемого _GoStringPtr. Обратите внимание, что содержимое строки может не иметь завершающего байта NUL.

Поскольку Go не поддерживает тип C union в общем случае, типы C union представляются в виде байтового массива Go одинаковой длины.

Структуры Go не могут вставлять поля с типами C.

Код Go не может ссылаться на поля нулевого размера, которые появляются в конце непустых структур C. Чтобы получить адрес такого поля (это единственная операция, которую вы можете выполнить с полем нулевого размера), вы должны взять адрес структуры и добавить размер структуры.

Cgo переводит типы C в эквивалентные неэкспортированные типы Go. Поскольку переводы не экспортируются, пакет Go не должен предоставлять типы C в своем экспортированном API: тип C, используемый в одном пакете Go, отличается от того же типа C, который используется в другом.

Любая функция C (даже функции void) может быть вызвана в контексте множественного присваивания, чтобы получить как возвращаемое значение (если оно есть), так и переменную C errno как ошибку (используйте _, чтобы пропустить значение результата, если функция возвращает void). Например:

n, err = C.sqrt(-1)
_, err := C.voidFunc()
var n, err = C.sqrt(1)

Вызов указателей на функции C в настоящее время не поддерживается, однако вы можете объявить переменные Go, которые содержат указатели на функции C и передавать их между Go и C. Код C может вызывать указатели на функции, полученные из Go. Например:

package main

// typedef int (*intFunc) ();
//
// int
// bridge_int_func(intFunc f)
// {
//    return f();
// }
//
// int fortytwo()
// {
//      return 42;
// }
import "C"
import "fmt"
func main() {
  f := C.intFunc(C.fortytwo)
  fmt.Println(int(C.bridge_int_func(f)))
  // Output: 42
}

В C аргумент функции, записанный как массив фиксированного размера, фактически требует указатель на первый элемент массива. Компиляторы C знают об этом соглашении о вызовах и корректируют вызов соответствующим образом, но Go не может. В Go вы должны явно передать указатель на первый элемент: C.f(&C.x[0]).

Вызов переменных функций C (variadic C functions) не поддерживается. Это можно обойти, используя обертку функции C (C function wrapper). Например:

package main

// #include <stdio.h>
// #include <stdlib.h>
//
// static void myprint(char* s) {
//   printf("%s\n", s);
// }
import "C"
import "unsafe"

func main() {
  cs := C.CString("Hello from stdio")
  C.myprint(cs)
  C.free(unsafe.Pointer(cs))
}

Несколько специальных функций конвертируют между типами Go и C, делая копии данных. В псевдо-Go определениях:

// Go строка в C строку
// Строка C размещается в куче C (C heap) с помощью malloc.
// Освобождение памяти это ответственность вызывающего, 
// например, вызвав C.free (обязательно включите stdlib.h
// если нужен C.free).
func C.CString(string) *C.char

// Go []byte срез в массив C (C array)
// Массив C размещается в куче C ( C heap) с помощью malloc.
// Освобождение памяти это ответственность вызывающего, 
// например, вызвав C.free (обязательно включите stdlib.h
// если нужен C.free).
func C.CBytes([]byte) unsafe.Pointer

// C строка в Go строку 
func C.GoString(*C.char) string

// Данные C с явной длиной в Go строку
func C.GoStringN(*C.char, C.int) string

// Данные C с явной длиной в Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte

В особом случае C.malloc не вызывает напрямую библиотеку C malloc, а вместо этого вызывает вспомогательную функцию Go, которая упаковывает библиотеку C malloc, но гарантирует, что она никогда не вернет nil. Если malloc C указывает на нехватку памяти, вспомогательная функция завершает работу программы, например, когда самому Go не хватает памяти. Поскольку C.malloc не может потерпеть неудачу, у него нет формы с двумя результатами, которая возвращает errno.


Читайте также:


суббота, 13 июля 2019 г.

Команда cgo, использование cgo с командой go

Cgo позволяет создавать пакеты Go, которые вызывают C код.

Использование cgo с командой go

Чтобы использовать cgo, напишите обычный код Go, который импортирует псевдопакет "C". Затем код Go может ссылаться на типы, такие как C.size_t, переменные, такие как C.stdout, или функции, такие как C.putchar.

Если импорту "C" сразу предшествует комментарий, этот комментарий, называемый преамбулой, используется в качестве заголовка при компиляции частей C пакета. Например:

// #include <stdio.h>
// #include <errno.h>
import "C"

Преамбула может содержать любой код на C, включая объявления и определения функций и переменных. Затем они могут быть переданы из кода Go, как если бы они были определены в пакете "C". Могут использоваться все имена, объявленные в преамбуле, даже если они начинаются со строчной буквы. Исключение: на статические переменные в преамбуле нельзя ссылаться из кода Go; статические функции разрешены.

Смотрите примеры в $GOROOT/misc/cgo/stdio и $GOROOT/misc/cgo/gmp.

CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS и LDFLAGS могут быть определены с помощью псевдо-директив #cgo в этих комментариях для настройки поведения компилятора C, C++ или Fortran. Значения, определенные в нескольких директивах, объединяются вместе. Директива может включать список ограничений сборки, ограничивающих его действие системами, удовлетворяющими одному из ограничений. Например:

// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"

В качестве альтернативы, CPPFLAGS и LDFLAGS можно получить с помощью инструмента pkg-config, используя директиву #cgo pkg-config:, за которой следуют имена пакетов. Например:

// #cgo pkg-config: png cairo
// #include <png.h>
import "C"

Инструмент pkg-config по умолчанию можно изменить, установив переменную среды PKG_CONFIG.

По соображениям безопасности разрешен только ограниченный набор флагов, в частности -D, -I и -l. Чтобы разрешить дополнительные флаги, установите для CGO_CFLAGS_ALLOW регулярное выражение, совпадающее с новыми флагами. Чтобы запретить флаги, которые в противном случае были бы разрешены, установите для CGO_CFLAGS_DISALLOW регулярное выражение, совпадающее с аргументами, которые должны быть запрещены. В обоих случаях регулярное выражение должно соответствовать полному аргументу: чтобы разрешить -mfoo=bar, используйте CGO_CFLAGS_ALLOW='-mfoo.*', А не только CGO_CFLAGS_ALLOW='-mfoo'. Переменные с одинаковыми именами управляют разрешенными CPPFLAGS, CXXFLAGS, FFLAGS и LDFLAGS.

Также по соображениям безопасности разрешен только ограниченный набор символов, в частности буквенно-цифровые символы и несколько символов, таких как '.', которые не будут интерпретироваться неожиданным образом. Попытки использовать запрещенные символы приведут к ошибке "malformed #cgo argument".

При сборке переменные среды CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS и CGO_LDFLAGS добавляются к флагам, полученным из этих директив. Флаги, специфичные для пакета, должны быть установлены с использованием директив, а не переменных среды, чтобы сборки работали в неизмененных средах. Флаги, полученные из переменных среды, не подпадают под ограничения безопасности, описанные выше.

Все директивы cgo CPPFLAGS и CFLAGS в пакете объединяются и используются для компиляции файлов C в этом пакете. Все директивы CPPFLAGS и CXXFLAGS в пакете объединяются и используются для компиляции файлов C++ в этом пакете. Все директивы CPPFLAGS и FFLAGS в пакете объединяются и используются для компиляции файлов Fortran в этом пакете. Все директивы LDFLAGS в любом пакете программы объединяются и используются во время соединения (link time). Все директивы pkg-config объединяются и отправляются в pkg-config одновременно для добавления к каждому соответствующему набору флагов командной строки.

Когда директивы cgo анализируются, любое вхождение строки ${SRCDIR} будет заменено абсолютным путем к каталогу, содержащему исходный файл. Это позволяет предварительно скомпилированным статическим библиотекам быть включенными в каталог пакета и правильно связанными. Например, если пакет foo находится в каталоге /go/src/foo:

// #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo

Будет расширен до:

// #cgo LDFLAGS: -L/go/src/foo/libs -lfoo

Когда инструмент Go видит, что один или несколько файлов Go используют специальный импорт "C", он ищет другие не-Go файлы в каталоге и компилирует их как часть пакета Go. Любые файлы .c, .s или .S будут скомпилированы с помощью компилятора C. Любые файлы .cc, .cpp или .cxx будут скомпилированы с помощью компилятора C++. Любые файлы .f, .F, .for или .f90 будут скомпилированы с помощью компилятора fortran. Любые файлы .h, .hh, .hpp или .hxx не будут скомпилированы отдельно, но, если эти файлы заголовков будут изменены, пакет (включая его исходные файлы не из Go) будет перекомпилирован. Обратите внимание, что изменения файлов в других каталогах не приводят к перекомпиляции пакета, поэтому весь не-Go исходный код для пакета должен храниться в каталоге пакета, а не в подкаталогах. Компиляторы C и C++ по умолчанию могут быть изменены переменными среды CC и CXX соответственно; эти переменные среды могут включать параметры командной строки.

Инструмент cgo включен по умолчанию для собственных сборок в системах, где он должен работать. По умолчанию это отключено при кросс-компиляции. Вы можете управлять этим, установив переменную окружения CGO_ENABLED при запуске инструмента go: установите его в 1, чтобы разрешить использование cgo, и в 0, чтобы отключить его. Инструмент go установит ограничение сборки "cgo", если включен cgo. Специальный импорт "C" подразумевает ограничение сборки "cgo", как будто файл также говорит "// +build cgo". Поэтому, если cgo отключен, файлы, импортирующие "C", не будут создаваться инструментом go.

При кросс-компиляции вы должны указать кросс-компилятор C для использования cgo. Вы можете сделать это, установив универсальную переменную среды CC_FOR_TARGET или более конкретную переменную среды CC_FOR_${GOOS}_${GOARCH} (например, CC_FOR_linux_arm) при построении цепочки инструментов с помощью make.bash, или вы можете установить переменную среды CC в любое время когда вы запускаете инструмент Go.

Переменные окружения CXX_FOR_TARGET, CXX_FOR_${GOOS}_${GOARCH} и CXX работают аналогичным образом для кода C++.


Читайте также:


Команда cover в Golang

cover - это программа для анализа профилей покрытия, сгенерированных с помощью 'go test -coverprofile=cover.out'.

cover также используется 'go test -cover', чтобы переписать исходный код с аннотациями, чтобы отслеживать, какие части каждой функции выполняются. Он работает с одним исходным файлом Go за раз, вычисляя приблизительную базовую информацию блока, изучая источник. Таким образом, он более переносим, чем инструменты покрытия с бинарным переписыванием, но также немного менее способен. Например, он не проверяет внутри && и || выражений, и может быть слегка запутан единичными утверждениями с несколькими функциональными литералами.

При вычислении покрытия пакета, в котором используется cgo, инструмент вывода должен применяться к выходным данным предварительной обработки cgo, а не к входным данным, поскольку cover удаляет комментарии, важные для cgo.

Для информации об использовании, смотрите:

go help testflag
go tool cover -help

go tool cover

Использование go tool cover:

Учитывать профиль покрытия, созданный в 'go test':

go test -coverprofile=c.out


Открыть веб-браузер с аннотированным исходным кодом:

go tool cover -html=c.out


Записать файл HTML вместо запуска веб-браузера:

go tool cover -html=c.out -o coverage.html


Отобразить процент покрытия на стандартный вывод для каждой функции:

go tool cover -func=c.out


Наконец, для генерации модифицированного исходного кода с аннотациями покрытия (что делает go test -cover):

go tool cover -mode=set -var=CoverageVariableName program.go


Флаги:

-V 
  напечатать версию и выйти
-func string
  вывод информации о профиле покрытия для каждой функции
-html string
  генерировать HTML-представление профиля покрытия
-mode string
  режим покрытия: set, count, atomic
-o string
  файл для вывода; по умолчанию: stdout
-var string
  имя создаваемой переменной покрытия 
  (по умолчанию "GoCover")

Одновременно может быть установлен только один из -html, -func или -mode.


Читайте также:


Функции тестирования в Golang

Команда 'go test' предполагает найти функции test, benchmark и example в файлах *_test.go, соответствующих тестируемому пакету.

Тестовая функция называется TestXxx (где Xxx не начинается со строчной буквы) и должна иметь сигнатуру,

func TestXxx(t *testing.T) { ... }

Контрольная функция называется BenchmarkXxx и должна иметь сигнатуру,

func BenchmarkXxx(b *testing.B) { ... }

Функция example похожа на функцию test, но вместо использования *testing.T для сообщения об успехе или неудаче выводит вывод в os.Stdout. Если последний комментарий в функции начинается с "Output:", то результат сравнивается точно с комментарием (см. Примеры ниже). Если последний комментарий начинается с "Unordered output:", то результат сравнивается с комментарием, однако порядок строк игнорируется. Пример без такого комментария компилируется, но не выполняется. Пример без текста после "Output:" компилируется, выполняется и, как ожидается, не будет производить вывод.

Godoc отображает тело ExampleXxx, чтобы продемонстрировать использование функции, константы или переменной Xxx. Пример метода M с типом получателя T или *T называется ExampleT_M. Может быть несколько примеров для данной функции, константы или переменной, отличающихся завершающим _xxx, где xxx - суффикс, не начинающийся с заглавной буквы.

Вот пример example:

func ExamplePrintln() {
    Println("The output of\nthis example.")
    // Output: The output of
    // this example.
}

Вот еще один пример, где порядок вывода игнорируется:

func ExamplePerm() {
    for _, value := range Perm(4) {
        fmt.Println(value)
    }

    // Unordered output: 4
    // 2
    // 1
    // 3
    // 0
}

Весь тестовый файл представлен в качестве example, когда он содержит одну example функцию, по крайней мере, одну другую функцию, тип, переменную или объявление константы, и не содержит test или benchmark функций.


Читайте также: