понедельник, 31 августа 2020 г.

Пакет strings в Golang, функция Compare

func Compare(a, b string) int

Compare возвращает целое число, сравнивая две строки лексикографически. Результатом будет 0, если a == b, -1, если a < b, и +1, если a > b.

Compare включена только для симметрии с пакетом bytes. Обычно проще и быстрее использовать встроенные операторы сравнения строк ==, <, > и так далее.

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

package main

import (
    "fmt"
    "strings"
)

func main() {
    fmt.Println(strings.Compare("a", "b"))
    fmt.Println(strings.Compare("a", "a"))
    fmt.Println(strings.Compare("b", "a"))
}

Вывод:

-1
0
1

В подтверждение слов о том, что функция реализована только для симмертрии с пакетом bytes, взглянем на реализацию функции в пакете strings:

package strings

func Compare(a, b string) int {
    if a == b {
      return 0
    }
    if a < b {
      return -1
    }
    return +1
}

Как видно из кода - функция внутри сама использует операторы == и <.


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


четверг, 27 августа 2020 г.

Пакет pprof в Golang

Пакет pprof обслуживает данные профилирования среды выполнения HTTP-сервера в формате, ожидаемом инструментом визуализации pprof.

Пакет обычно импортируется только из-за побочного эффекта регистрации его обработчиков HTTP. Все обрабатываемые пути начинаются с /debug/pprof/.

Чтобы использовать pprof, свяжите этот пакет со своей программой:

import _ "net/http/pprof"

Если ваше приложение еще не запустило http-сервер, вам необходимо запустить его. Добавьте "net/http" и "log" к вашему импорту и следующий код к вашей main функции:

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()

Если вы не используете DefaultServeMux, вам нужно будет зарегистрировать обработчики в используемом мультиплексоре (mux). Например:

package main

import (
    "log"
    "net/http"
    "net/http/pprof"
)

func main() {
    mux := http.NewServeMux()

    // Здесь можно указать свой путь
    mux.HandleFunc("/debug/pprof/profile", pprof.Profile)

    log.Fatal(http.ListenAndServe(":6060", mux))
}

Затем используйте инструмент pprof, чтобы посмотреть профиль кучи (heap profile):

go tool pprof http://localhost:6060/debug/pprof/heap

Или посмотреть 30-секундный профиль процессора:

go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30

Или посмотреть профиль блокировки goroutine после вызова runtime.SetBlockProfileRate в вашей программе:

go tool pprof http://localhost:6060/debug/pprof/block

Или посмотреть на держателей конкурирующих мьютексов после вызова runtime.SetMutexProfileFraction в вашей программе:

go tool pprof http://localhost:6060/debug/pprof/mutex

Пакет также экспортирует обработчик, который обслуживает данные трассировки выполнения для команды "go tool trace". Чтобы собрать 5-секундную трассировку выполнения:

wget -O trace.out http://localhost:6060/debug/pprof/trace?seconds=5
go tool trace trace.out

Чтобы просмотреть все доступные профили, откройте в браузере http://localhost:6060/debug/pprof/.

Функция Cmdline

func Cmdline(w http.ResponseWriter, r *http.Request)

Cmdline отвечает командной строкой запущенной программы с аргументами, разделенными NUL байтами. Инициализация пакета регистрирует его как /debug/pprof/cmdline.

Функция Handler

func Handler(name string) http.Handler

Handler возвращает обработчик HTTP, который обслуживает именованный профиль.

Функция Index

func Index(w http.ResponseWriter, r *http.Request)

Index отвечает профилем в формате pprof, указанным в запросе. Например, "/debug/pprof/heap" обслуживает профиль "heap". Index отвечает на запрос "/debug/pprof/" HTML-страницей со списком доступных профилей.

Функция Profile

func Profile(w http.ResponseWriter, r *http.Request)

Profile отвечает профилем процессора в формате pprof. Профилирование длится в течение времени, указанного в параметре GET в секундах, или 30 секунд, если не указано иное. Инициализация пакета регистрирует его как /debug/pprof/profile.

Функция Symbol

func Symbol(w http.ResponseWriter, r *http.Request)

Symbol ищет программные счетчики, перечисленные в запросе, отвечая таблицей, отображающей программные счетчики на имена функций. Инициализация пакета регистрирует его как /debug/pprof/symbol.

Функция Trace

func Trace(w http.ResponseWriter, r *http.Request)

Trace отвечает трассировкой выполнения в двоичной форме. Трассировка длится в течение времени, указанного в параметре GET в секундах, или в течение 1 секунды, если не указано иное. Инициализация пакета регистрирует его как /debug/pprof/trace.


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


суббота, 22 августа 2020 г.

Пакет httptrace в Golang

Пакет httptrace предоставляет механизмы для отслеживания событий в клиентских HTTP-запросах.

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

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httptrace"
)

func main() {
    req, _ := http.NewRequest("GET", "http://example.com", nil)
    trace := &httptrace.ClientTrace{
        GotConn: func(connInfo httptrace.GotConnInfo) {
            fmt.Printf("Got Conn: %+v\n", connInfo)
        },
        DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
            fmt.Printf("DNS Info: %+v\n", dnsInfo)
        },
    }
    req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
    _, err := http.DefaultTransport.RoundTrip(req)
    if err != nil {
        log.Fatal(err)
    }
}

Функция WithClientTrace

func WithClientTrace(ctx context.Context, trace *ClientTrace) context.Context

WithClientTrace возвращает новый контекст на основе предоставленного родительского ctx. Запросы клиента HTTP, сделанные с возвращенным контекстом, будут использовать предоставленные перехватчики трассировки в дополнение к любым предыдущим перехватчикам, зарегистрированным с помощью ctx. Любые хуки, определенные в предоставленной трассировке, будут вызываться первыми.

Тип ClientTrace

ClientTrace - это набор перехватчиков для запуска на различных этапах исходящего HTTP-запроса. Любой конкретный хук может быть nil. Функции могут вызываться одновременно из разных goroutines, а некоторые из них могут вызываться после завершения или сбоя запроса.

ClientTrace в настоящее время отслеживает один HTTP-запрос и ответ в течение одного цикла и не имеет перехватчиков, которые охватывают серию перенаправленных запросов.

type ClientTrace struct {
    // GetConn вызывается 
    // перед созданием соединения или
    // извлекается из неактивного пула. 
    // hostPort - это "host:port" 
    // цели или прокси. 
    // GetConn называется даже
    // если уже доступно незанятое 
    // кэшированное соединение.
    GetConn func(hostPort string)

    // GotConn вызывается после 
    // успешного получения подключения.
    // Нет никакого хука 
    // для неуспешного получения соединения; 
    // вместо этого используйте ошибку из 
    // Transport.RoundTrip.
    GotConn func(GotConnInfo)

    // PutIdleConn вызывается, 
    // когда соединение возвращается в пул ожидания.
    // Если err равен nil, соединение было
    // успешно возвращено в пул ожидания. 
    // Если err не равно nil, объясняет, почему нет. 
    // PutIdleConn не вызывается, если
    // повторное использование соединения 
    // отключено через Transport.DisableKeepAlives.
    // PutIdleConn вызывается до 
    // возврата вызов Response.Body.Close.
    // Для HTTP/2 этот хук в настоящее время не используется.
    PutIdleConn func(err error)

    // GotFirstResponseByte вызывается, 
    // когда первый байт заголовков ответа доступен.
    GotFirstResponseByte func()

    // Got100Continue вызывается, 
    // если сервер отвечает "100 Continue"
    Got100Continue func()

    // Got1xxResponse вызывается для каждого 
    // информационного заголовка ответа 1xx
    // возвращается перед окончательным ответом, 
    // отличным от 1xx. Got1xxResponse называется
    // для ответов "100 Continue", 
    // даже если также определено Got100Continue.
    // Если он возвращает ошибку, 
    // клиентский запрос прерывается с этим значением ошибки.
    Got1xxResponse func(code int, header textproto.MIMEHeader) error // Go 1.11

    // DNSStart вызывается, когда начинается поиск DNS.
    DNSStart func(DNSStartInfo)

    // DNSDone вызывается по окончании поиска DNS.
    DNSDone func(DNSDoneInfo)

    // ConnectStart вызывается, 
    // когда начинается Dial нового соединения.
    // Если net.Dialer.DualStack 
    // (IPv6 "Happy Eyeballs") поддержка
    // включена, ConnectStart можно вызывать несколько раз.
    ConnectStart func(network, addr string)

    // ConnectDone вызывается 
    // когда Dial нового соединения завершается. 
    // Предоставленная err указывает,
    // успешно ли соединение завершено.
    // Если поддержка net.Dialer.DualStack ("Happy Eyeballs")
    // включена, ConnectDone можно вызывать несколько раз.
    ConnectDone func(network, addr string, err error)

    // TLSHandshakeStart вызывается, 
    // когда начинается рукопожатие TLS.
    // Когда подключаемся к HTTPS-сайту 
    // через HTTP-прокси, рукопожатие происходит 
    // после того, как запрос CONNECT обработан прокси.
    TLSHandshakeStart func() // Go 1.8

    // TLSHandshakeDone вызывается 
    // после TLS рукопожатие 
    // с успешным статусом соединения 
    // при успешном рукопожатии или 
    // есть ошибка, отличная от nil при сбое рукопожатия.
    TLSHandshakeDone func(tls.ConnectionState, error) // Go 1.8

    // WroteHeaderField вызывается 
    // после того, как Transport записал
    // заголовок каждого запроса. 
    // Во время этого вызова значения
    // могут быть буферизованы и еще не записаны в сеть.
    WroteHeaderField func(key string, value []string) // Go 1.11

    // WroteHeaders вызывается 
    // после того, как Transport записал
    // все заголовки запроса.
    WroteHeaders func()

    // Wait100Continue вызывается, если указан запрос
    // "Expect: 100-continue", и Transport записал
    // заголовки запроса, но ожидает "100 Continue" от
    // сервера перед записью тела запроса.
    Wait100Continue func()

    // WroteRequest вызывается с результатом записи
    // запроса и любого тела. Может вызываться несколько раз
    // в случае повторных запросов.
    WroteRequest func(WroteRequestInfo)
}

Функция ContextClientTrace

func ContextClientTrace(ctx context.Context) *ClientTrace

ContextClientTrace возвращает ClientTrace, связанный с предоставленным контекстом. Если нет, возвращается nil.

Тип DNSDoneInfo

DNSDoneInfo содержит информацию о результатах поиска DNS.

type DNSDoneInfo struct {
    // Addrs - это адреса IPv4 и/или IPv6, 
    // найденные в DNS поиске. 
    // Содержимое среза не должно изменяться.
    Addrs []net.IPAddr

    // Err - это любая ошибка, 
    // произошедшая во время поиска DNS.
    Err error

    // Coalesced флаг true если Addrs 
    // совместно использованы с другим вызывающим абонентом, 
    // который одновременно выполнял такой же поиск DNS.
    Coalesced bool
}

Тип DNSStartInfo

DNSStartInfo содержит информацию о DNS-запросе.

type DNSStartInfo struct {
    Host string
}

Тип GotConnInfo

GotConnInfo является аргументом функции ClientTrace.GotConn и содержит информацию о полученном соединении.

type GotConnInfo struct {
    // Conn - это полученное соединение. 
    // Оно принадлежит http.Transport 
    // и его нельзя читать, писать или
    // закрыть пользователями ClientTrace.
    Conn net.Conn

    // Reused равен true если это соединение
    // было ранее использовано для другого HTTP-запроса.
    Reused bool

    // WasIdle - было ли это соединение получено из
    // пула ожидания.
    WasIdle bool

    // IdleTime сообщает, 
    // сколько времени соединение 
    // ранее было бездействующим, 
    // если WasIdle истинно.
    IdleTime time.Duration
}

Тип WroteRequestInfo

WroteRequestInfo содержит информацию, предоставленную хуку WroteRequest.

type WroteRequestInfo struct {
    // Err - это любая ошибка, обнаруженная при записи запроса.
    Err error
}


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


вторник, 18 августа 2020 г.

Пакет httptest в Golang

Пакет httptest предоставляет утилиты для тестирования HTTP.

Функция NewRequest

func NewRequest(method, target string, body io.Reader) *http.Request

NewRequest возвращает новый входящий Request сервера, подходящий для передачи http.Handler для тестирования.

target является RFC 7230 "request-target": это может быть либо путь, либо абсолютный URL. Если target является абсолютный URL-адрес, используется имя хоста из URL-адреса. В противном случае используется example.com.

В поле TLS устанавливается фиктивное значение, отличное от nil, если target имеет схему "https".

Request.Proto всегда HTTP/1.1.

Пустой method означает "GET".

Предоставленное body может быть nil. Если тело имеет тип *bytes.Reader, *strings.Reader или *bytes.Buffer, устанавливается Request.ContentLength.

NewRequest паникует при ошибке для простоты использования при тестировании, где паника допустима.

Чтобы сгенерировать клиентский HTTP-запрос вместо запроса сервера, используйте функцию NewRequest в пакете net/http.

Тип ResponseRecorder

ResponseRecorder - это реализация http.ResponseWriter, которая записывает его изменения для последующей проверки в тестах.

type ResponseRecorder struct {
    // Code - это код ответа HTTP, 
    // установленный WriteHeader.
    //
    // Обратите внимание, что если Handler 
    // никогда не вызывает WriteHeader или Write,
    // Code может оказаться 0, 
    // а не неявным http.StatusOK. 
    // Чтобы получить неявное значение, 
    // используйте метод Result.
    Code int

    // HeaderMap содержит заголовки, 
    // явно установленные Handler.
    // Это внутренняя деталь.
    //
    // Не рекомендуется: 
    // HeaderMap существует для исторической совместимости
    // и не должны использоваться. 
    // Чтобы получить доступ к заголовкам, 
    // возвращаемым обработчиком,
    // использовать карту Response.Header, 
    // возвращенную методом Result.
    HeaderMap http.Header

    // Body - это буфер, 
    // в который отправляются вызовы Write Handler'а.
    // Если nil, Writes игнорируется.
    Body *bytes.Buffer

    // Flushed, флаг вызвал ли Handler Flush.
    Flushed bool
    // содержит отфильтрованные или неэкспортированные поля
}

Пример использования NewRequest, NewRecorder

package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
    "net/http/httptest"
)

func main() {
    handler := func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "<html><body>Hello World!</body></html>")
    }

    req := httptest.NewRequest("GET", "http://example.com/foo", nil)
    w := httptest.NewRecorder()
    handler(w, req)

    resp := w.Result()
    body, _ := ioutil.ReadAll(resp.Body)

    fmt.Println(resp.StatusCode)
    fmt.Println(resp.Header.Get("Content-Type"))
    fmt.Println(string(body))

}

Вывод:

200
text/html; charset=utf-8
<html><body>Hello World!</body></html>

Тип Server

Server - это HTTP-сервер, который прослушивает выбранный системой порт на локальном интерфейсе обратной связи для использования в сквозных (end-to-end) HTTP-тестах.

type Server struct {
    // базовый URL формы 
    // http://ipaddr:port без слеша в конце
    URL      string 
    Listener net.Listener

    // EnableHTTP2 контролирует, включен ли HTTP/2
    // на сервере. Он должен быть установлен между вызовами
    // NewUnstartedServer и Server.StartTLS.
    EnableHTTP2 bool // Go 1.14

    // TLS - это необязательная конфигурация TLS, 
    // заполненная новой конфигурацией после запуска TLS. 
    // Если установлено на 
    // не запущенном сервере до вызова StartTLS,
    // существующие поля копируются в новый конфиг.
    TLS *tls.Config

    // Config может быть изменен 
    // после вызова NewUnstartedServer и
    // перед Start или StartTLS.
    Конфиг *http.Server
    // содержит отфильтрованные или неэкспортированные поля
}

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

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httptest"
)

func main() {
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello, client")
    }))
    defer ts.Close()

    res, err := http.Get(ts.URL)
    if err != nil {
        log.Fatal(err)
    }
    greeting, err := ioutil.ReadAll(res.Body)
    res.Body.Close()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%s", greeting)
}

Вывод:

Hello, client

Пример использования Server (HTTP2)

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httptest"
)

func main() {
    ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, %s", r.Proto)
    }))
    ts.EnableHTTP2 = true
    ts.StartTLS()
    defer ts.Close()

    res, err := ts.Client().Get(ts.URL)
    if err != nil {
        log.Fatal(err)
    }
    greeting, err := ioutil.ReadAll(res.Body)
    res.Body.Close()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s", greeting)

}

Вывод:

Hello, HTTP/2.0

Функция NewServer

func NewServer(handler http.Handler) *Server

NewServer запускается и возвращает новый Server. По завершении вызывающий должен вызвать Close, чтобы закрыть его.

Функция NewTLSServer

func NewTLSServer(handler http.Handler) *Server

NewTLSServer запускается и возвращает новый Server с использованием TLS. По завершении вызывающий должен вызвать Close, чтобы закрыть его.

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

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httptest"
)

func main() {
    ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello, client")
    }))
    defer ts.Close()

    client := ts.Client()
    res, err := client.Get(ts.URL)
    if err != nil {
        log.Fatal(err)
    }

    greeting, err := ioutil.ReadAll(res.Body)
    res.Body.Close()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%s", greeting)
}

Вывод:

Hello, client


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


суббота, 15 августа 2020 г.

Релиз Go 1.15, основная библиотека

Новый встроенный пакет tzdata

Go 1.15 включает новый пакет time/tzdata, который позволяет встраивать базу данных часовых поясов в программу. Импорт этого пакета (как import _ "time/tzdata") позволяет программе находить информацию о часовом поясе, даже если база данных часовых поясов недоступна в локальной системе. Вы также можете встроить базу данных часовых поясов, создав с помощью -tags timetzdata. При любом подходе размер программы увеличивается примерно на 800 КБ.

Cgo

Go 1.15 преобразует C-тип EGLConfig в Go-тип uintptr. Это изменение аналогично тому, как Go 1.12 и новее обрабатывает типы EGLDisplay, Darwin CoreFoundation и Java JNI.

Прекращение поддержки X.509 CommonName

Устаревшее поведение, заключающееся в обработке поля CommonName в сертификатах X.509 как имени хоста при отсутствии альтернативных имен субъектов, теперь по умолчанию отключено. Его можно временно снова включить, добавив значение x509ignoreCN=0 в переменную среды GODEBUG.

Обратите внимание, что если CommonName является недопустимым именем хоста, оно всегда игнорируется, независимо от настроек GODEBUG. К недопустимым именам относятся имена с любыми символами, кроме букв, цифр, дефисов и подчеркиваний, а также имена с пустыми метками или конечными точками.

Незначительные изменения в библиотеке

Как всегда, в библиотеку внесены различные незначительные изменения и обновления, сделанные с учетом обещания совместимости с Go 1.

bufio

Когда Scanner используется с недопустимым io.Reader, который неправильно возвращает отрицательное число из Read, Scanner больше не паникует, а вместо этого вернет новую ошибку ErrBadReadCount.

context

Создание производного Context с использованием родительского nil элемента теперь явно запрещено. Любая попытка сделать это с помощью функций WithValue, WithDeadline или WithCancel вызовет панику.

crypto

Типы PrivateKey и PublicKey в пакетах crypto/rsa, crypto/ecdsa и crypto/ed25519 теперь имеют метод Equal для сравнения ключей на эквивалентность или для создания интерфейсов с типобезопасностью для публичных ключей. Сигнатура метода совместима с определением равенства go-cmp.

Hash теперь реализует fmt.Stringer.

crypto/ecdsa

Новые функции SignASN1 и VerifyASN1 позволяют генерировать и проверять подписи ECDSA в стандартной кодировке DER ASN.1.

crypto/elliptic

Новые функции MarshalCompressed и UnmarshalCompressed позволяют кодировать и декодировать точки эллиптических кривых NIST в сжатом формате.

crypto/rsa

VerifyPKCS1v15 теперь отклоняет недопустимые короткие подписи с отсутствующими ведущими нулями в соответствии с RFC 8017.

crypto/tls

Новый тип Dialer и его метод DialContext позволяют использовать контекст как для подключения, так и для обмена рукопожатиями с сервером TLS.

Новый обратный вызов VerifyConnection для типа Config позволяет настраивать логику проверки для каждого соединения. Он имеет доступ к ConnectionState, который включает сертификаты одноранговых узлов (peer certificates), SCT и сшитые ответы OCSP.

Автоматически сгенерированные ключи билета сеанса теперь автоматически меняются каждые 24 часа со сроком действия 7 дней, чтобы ограничить их влияние на прямую секретность.

Время жизни сеансового билета в TLS 1.2 и более ранних версиях, где ключи сеанса повторно используются для возобновленных подключений, теперь ограничено 7 днями, чтобы ограничить их влияние на прямую секретность.

Проверки защиты от перехода на более раннюю версию на стороне клиента, указанные в RFC 8446, теперь применяются. Это может вызвать ошибки подключения для клиентов, сталкивающихся с промежуточными ящиками, которые ведут себя как атаки с несанкционированным переходом на более раннюю версию.

SignatureScheme, CurveID и ClientAuthType теперь реализуют fmt.Stringer.

Поля ConnectionState OCSPResponse и SignedCertificateTimestamps теперь повторно заполняются для возобновленных подключений на стороне клиента.

tls.Conn теперь возвращает непрозрачную ошибку при постоянно разорванных соединениях, оборачивая временную net.Error. Чтобы получить доступ к исходной net.Error, используйте errors.As (или errors.Unwrap) вместо утверждения типа.

crypto/x509

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

Новая функция CreateRevocationList и тип RevocationList позволяют создавать списки отозванных сертификатов X.509 v2, соответствующие RFC 5280.

CreateCertificate теперь автоматически генерирует SubjectKeyId, если шаблон является центром сертификации и не указывает его явно.

CreateCertificate теперь возвращает ошибку, если в шаблоне указан MaxPathLen, но он не является центром сертификации.

В системах Unix, отличных от macOS, переменная среды SSL_CERT_DIR теперь может быть списком, разделенным двоеточиями.

В macOS двоичные файлы теперь всегда связаны с Security.framework для извлечения системных доверенных корней, независимо от того, доступно ли cgo. Полученное поведение должно быть более согласованным с верификатором ОС.

crypto/x509/pkix

Name.String теперь печатает нестандартные атрибуты из имен, если ExtraNames равно nil.

database/sql

Новый метод DB.SetConnMaxIdleTime позволяет удалить соединение из пула соединений после того, как оно какое-то время бездействовало, без учета общего срока жизни соединения. Поле DBStats.MaxIdleTimeClosed показывает общее количество соединений, закрытых из-за DB.SetConnMaxIdleTime.

Новый метод получения Row.Err позволяет проверять ошибки запроса без вызова Row.Scan.

database/sql/driver

Новый интерфейс Validator может быть реализован Conn, чтобы позволить драйверам сигнализировать, действительно ли соединение или его следует отменить.

debug/pe

Пакет теперь определяет константы IMAGE_FILE, IMAGE_SUBSYSTEM и IMAGE_DLLCHARACTERISTICS, используемые форматом файла PE.

encoding/asn1

Marshal теперь сортирует компоненты SET OF в соответствии с X.690 DER.

Unmarshal теперь отклоняет теги и идентификаторы объектов, которые минимально не закодированы в соответствии с X.690 DER.

encoding/json

Пакет теперь имеет внутреннее ограничение на максимальную глубину вложенности при декодировании. Это снижает вероятность того, что глубоко вложенный ввод может использовать большие объемы памяти стека или даже вызвать панику "goroutine stack exceeds limit".

flag

Когда пакет flag видит -h или -help, а эти флаги не определены, он теперь печатает сообщение об использовании. Если FlagSet был создан с ExitOnError, FlagSet.Parse будет завершен со статусом 2. В этом релизе статус выхода для -h или -help изменен на 0. В частности, это относится к обработке по умолчанию флагов коммандной строки.

fmt

Команды печати %#g и %#G теперь сохраняют конечные нули для значений с плавающей запятой.

go/format

Функции Source и Node теперь канонизируют префиксы и показатели числовых литералов как часть форматирования исходного кода Go. Это соответствует поведению команды gofmt, реализованной начиная с Go 1.13.

html/template

В пакете теперь используются escape-символы Unicode (\uNNNN) во всех контекстах JavaScript и JSON. Это исправляет ошибки экранирования в контекстах application/ld+json и application/json.

io/ioutil

TempDir и TempFile теперь отклоняют шаблоны, содержащие разделители путей. То есть такие вызовы, как ioutil.TempFile("/tmp", "../base*") больше не будут успешными. Это предотвращает непреднамеренный обход каталога.

math/big

Новый метод Int.FillBytes позволяет сериализовать в заранее выделенные байтовые срезы фиксированного размера.

math/cmplx

Функции в этом пакете были обновлены для соответствия стандарту C99 (приложение G, совместимое с IEC 60559 комплексная арифметика) в отношении обработки специальных аргументов, таких как бесконечность, NaN и ноль со знаком.

net

Если операция ввода-вывода превышает крайний срок, установленный методами Conn.SetDeadline, Conn.SetReadDeadline или Conn.SetWriteDeadline, она теперь будет возвращать ошибку, которая является os.ErrDeadlineExceeded или обертывает ее. Это может использоваться для надежного определения того, является ли ошибка следствием превышения крайнего срока. В более ранних выпусках рекомендовалось вызывать метод Timeout при ошибке, но операции ввода-вывода могут возвращать ошибки, для которых Timeout возвращает true, хотя крайний срок не был превышен.

Новый метод Resolver.LookupIP поддерживает поиск IP-адресов, который зависит от сети и принимает контекст.

net/http

Синтаксический анализ теперь является более строгой мерой защиты от атак контрабанды запросов (request smuggling attacks): пробелы, не относящиеся к ASCII, больше не обрезаются, как SP и HTAB, а поддержка "идентификационного" Transfer-Encoding была прекращена.

net/http/httputil

ReverseProxy теперь поддерживает запрет на изменение заголовка X-Forwarded-For, когда входящая запись карты Request.Header для этого поля равна nil.

Когда запрос протокола переключения (например, WebSocket), обрабатываемый ReverseProxy, отменяется, серверное соединение теперь закрывается правильно.

net/http/pprof

Все конечные точки профиля теперь поддерживают параметр "seconds". Если присутствует, конечная точка профилирует указанное количество секунд и сообщает о разнице. Значение параметра "seconds" в профиле процессора и конечных точек трассировки не изменилось.

net/url

Новое поле URL-адреса RawFragment и метод EscapedFragment предоставляют подробную информацию о точном кодировании конкретного фрагмента и контролируют его. Они аналогичны RawPath и EscapedPath.

Новый метод URL-адреса Redacted возвращает URL-адрес в строковой форме с заменой любого пароля на xxxxx.

os

Если операция ввода-вывода превышает крайний срок, установленный методами File.SetDeadline, File.SetReadDeadline или File.SetWriteDeadline, теперь она будет возвращать ошибку, которая является или обертывает os.ErrDeadlineExceeded. Это может использоваться для надежного определения того, является ли ошибка следствием превышения крайнего срока. В более ранних выпусках рекомендовалось вызывать метод Timeout при ошибке, но операции ввода-вывода могут возвращать ошибки, для которых Timeout возвращает true, хотя крайний срок не был превышен.

Пакеты os и net теперь автоматически повторяют системные вызовы, которые завершаются ошибкой с EINTR. Раньше это приводило к ложным сбоям, которые стали более распространенными в Go 1.14 с добавлением асинхронного прерывания. Теперь это делается прозрачно.

Тип os.File теперь поддерживает метод ReadFrom. Это позволяет использовать системный вызов copy_file_range в некоторых системах при использовании io.Copy для копирования данных из одного файла os.File в другой. Как следствие, io.CopyBuffer не всегда будет использовать указанный буфер при копировании в os.File. Если программа хочет принудительно использовать предоставленный буфер, это можно сделать, написав io.CopyBuffer(struct{ io.Writer }{dst}, src, buf).

plugin

Генерация DWARF теперь поддерживается (и включена по умолчанию) для -buildmode=plugin в macOS.

Сборка с -buildmode=plugin теперь поддерживается на freebsd/amd64.

reflect

Пакет reflect теперь запрещает доступ к методам всех неэкспортируемых полей, тогда как ранее он разрешал доступ к методам неэкспортированных встроенных полей. Код, основанный на предыдущем поведении, следует обновить, чтобы вместо этого получить доступ к соответствующему продвинутому методу включающей переменной.

regexp

Новый метод Regexp.SubexpIndex возвращает индекс первого подвыражения с заданным именем в регулярном выражении.

runtime

Некоторые функции, включая ReadMemStats и GoroutineProfile, больше не блокируются, если выполняется сборка мусора.

runtime/pprof

Профиль goroutine теперь включает метки профиля, связанные с каждой goroutine во время профилирования. Эта функция еще не реализована для профиля, о котором сообщается с debug=2.

strconv

FormatComplex и ParseComplex добавлены для работы с комплексными числами.

FormatComplex преобразует комплексное число в строку формы (a+bi), где a и b - действительная и мнимая части.

ParseComplex преобразует строку в комплексное число заданной точности. ParseComplex принимает комплексные числа в формате N+Ni.

sync

Новый метод Map.LoadAndDelete атомарно удаляет ключ и возвращает предыдущее значение, если оно есть.

Метод Map.Delete более эффективен.

syscall

В системах Unix функции, использующие SysProcAttr, теперь будут отклонять попытки установить оба поля Setctty и Foreground, поскольку они оба используют поле Ctty, но делают это несовместимыми способами. Ожидается, что некторые существующие программы устанавливают оба поля.

Для настройки поля Setctty теперь требуется, чтобы в поле Ctty был установлен номер дескриптора файла в дочернем процессе, как определено в поле ProcAttr.Files. Использование дочернего дескриптора всегда работало, но в некоторых случаях использование родительского файлового дескриптора также помогало. Некоторым программам, которые устанавливают Setctty, необходимо будет изменить значение Ctty, чтобы использовать номер дочернего дескриптора.

Теперь можно вызывать системные вызовы, возвращающие значения с плавающей запятой в windows/amd64.

testing

Тип testing.T теперь имеет метод Deadline, который сообщает время, когда тестовый двоичный файл превысит свой таймаут.

Функция TestMain больше не требуется для вызова os.Exit. Если функция TestMain вернется, тестовый двоичный файл вызовет os.Exit со значением, возвращаемым m.Run.

Новые методы T.TempDir и B.TempDir возвращают временные каталоги, которые автоматически очищаются в конце теста.

go test -v теперь группирует вывод по имени теста, а не печатает имя теста в каждой строке.

text/template

JSEscape теперь постоянно использует escape-символы Unicode (\u00XX), которые совместимы с JSON.

time

Новый метод Ticker.Reset поддерживает изменение длительности тикера.

При возврате ошибки ParseDuration теперь цитирует исходное значение.


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


купить игрушку gopher

пятница, 14 августа 2020 г.

Релиз Go 1.15, runtime, компилятор, компоновщик

Среда времени выполнения (Runtime)

Если паника вызывается со значением, тип которого является производным от любого из: bool, complex64, complex128, float32, float64, int, int8, int16, int32, int64, string, uint, uint8, uint16, uint32, uint64, uintptr, тогда будет напечатано значение, а не только его адрес. Раньше это было верно только для значений именно этих типов.

В системе Unix, если команда kill или системный вызов kill используется для отправки сигнала SIGSEGV, SIGBUS или SIGFPE программе Go, и если сигнал не обрабатывается через os/signal.Notify, программа Go теперь будет надежно вылетать с трассировкой стека. В более ранних выпусках поведение было непредсказуемым.

Распределение небольших объектов теперь работает намного лучше при большом количестве ядер и имеет меньшую задержку в худшем случае.

Преобразование небольшого целочисленного значения в значение интерфейса больше не вызывает выделения.

Неблокирующие приемы по закрытым каналам теперь работают так же, как неблокирующие приемы по открытым каналам.

Компилятор

Правила безопасности package unsafe позволяют конвертировать unsafe.Pointer в uintptr при вызове определенных функций. Ранее в некоторых случаях компилятор допускал несколько связанных преобразований (например, syscall.Syscall(…, uintptr(uintptr(ptr)), …)). Теперь компилятору требуется ровно одно преобразование. Код, в котором использовалось несколько преобразований, следует обновить, чтобы он соответствовал правилам безопасности.

Go 1.15 уменьшает типичный двоичный размер примерно на 5% по сравнению с Go 1.14 за счет исключения определенных типов метаданных GC и более активного удаления метаданных неиспользуемых типов.

Цепочка инструментов теперь смягчает ошибку CPU Intel SKX102 на GOARCH=amd64, выравнивая функции по 32-байтовым границам и заполняя инструкции перехода. Хотя это заполнение увеличивает двоичный размер, это более чем компенсируется упомянутыми выше улучшениями двоичного размера.

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

Теперь компилятор отклоняет компиляторные директивы //go: , которые не имеют значения для объявления, к которому они применяются, с ошибкой "неправильно размещенная директива компилятора". Такие неправильно примененные директивы ранее нарушались, но компилятор молча игнорировал их.

Ведение журнала оптимизации компилятора -json теперь сообщает о больших (>= 128 байт) копиях и включает объяснения решений анализа выхода.

Компновщик (Linker)

Этот выпуск включает в себя существенные улучшения компоновщика Go, которые сокращают использование ресурсов компоновщика (как время, так и память) и улучшают надежность кода/ремонтопригодность.

Для репрезентативного набора больших программ Go компоновка выполняется на 20% быстрее и требует в среднем на 30% меньше памяти для ОС на основе ELF (Linux, FreeBSD, NetBSD, OpenBSD, Dragonfly и Solaris), работающих на архитектурах amd64, с более скромными параметрами улучшения для других комбинаций архитектуры/ОС.

Ключевыми факторами повышения производительности компоновщика являются недавно переработанный формат объектного файла и переработка внутренних фаз для увеличения конкурентности (например, параллельное применение перемещений к символам). Объектные файлы в Go 1.15 немного больше, чем их эквиваленты в 1.14.

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

Компоновщик теперь по умолчанию использует режим внутренней компоновки для -buildmode=pie в linux/amd64 и linux/arm64, поэтому эти конфигурации больше не требуют компоновщика C.

Objdump

Инструмент objdump теперь поддерживает дизассемблирование в синтаксисе ассемблера GNU с флагом -gnu.


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


четверг, 13 августа 2020 г.

Релиз Go 1.15, порты, инструменты

Выпуск Go, версия 1.15, выходит через шесть месяцев после Go 1.14. Большинство его изменений связано с реализацией цепочки инструментов, среды выполнения и библиотек. Как всегда, релиз поддерживает обещание Go 1 совместимости. Ожидается, что почти все программы Go будут продолжать компилироваться и работать как раньше.

Go 1.15 включает в себя существенные улучшения компоновщика, улучшает распределение для небольших объектов при большом количестве ядер и не поддерживает X.509 CommonName. GOPROXY теперь поддерживает пропуск прокси, возвращающих ошибки, и был добавлен новый встроенный пакет tzdata.

Изменений в языке нет.

Порты


Darwin

Как было объявлено в примечаниях к выпуску Go 1.14, для Go 1.15 требуется macOS 10.12 Sierra или новее; поддержка предыдущих версий прекращена.

Как было объявлено в примечаниях к выпуску Go 1.14, Go 1.15 отказывается от поддержки 32-битных двоичных файлов в macOS, iOS, iPadOS, watchOS и tvOS (порты darwin/386 и darwin/arm). Go продолжает поддерживать 64-битные порты darwin/amd64 и darwin/arm64.

Windows

Go теперь генерирует исполняемые файлы Windows ASLR, если указан флаг -buildmode=pie cmd/link. Команда Go по умолчанию использует -buildmode=pie в Windows.

Флаги -race и -msan теперь всегда включают -d=checkptr, который проверяет использование unsafe.Pointer. Раньше так было во всех ОС, кроме Windows.

Собранные на Go библиотеки DLL больше не вызывают завершение процесса при получении сигнала (например, Ctrl-C на терминале).

Android

При компоновке двоичных файлов для Android Go 1.15 явно выбирает компоновщик lld, доступный в последних версиях NDK. Компоновщик lld позволяет избежать сбоев на некоторых устройствах, и планируется, что он станет компоновщиком NDK по умолчанию в будущей версии NDK.

OpenBSD

Go 1.15 добавляет поддержку OpenBSD 6.7 на GOARCH=arm и GOARCH=arm64. Предыдущие версии Go уже поддерживали OpenBSD 6.7 на GOARCH=386 и GOARCH=amd64.

RISC-V

Достигнут прогресс в улучшении стабильности и производительности 64-разрядного порта RISC-V в Linux (GOOS=linux, GOARCH=riscv64). Он также теперь поддерживает асинхронное прерывание.

386

Go 1.15 - последний выпуск, который поддерживает оборудование с плавающей запятой только для x87 (GO386=387). В будущих выпусках потребуется как минимум поддержка SSE2 на 386, что повысит минимальное требование Go для GOARCH=386 до Intel Pentium 4 (выпущенного в 2000 году) или AMD Opteron/Athlon 64 (выпущенного в 2003 году).

Инструменты

Команда Go

Переменная среды GOPROXY теперь поддерживает пропуск прокси, возвращающих ошибки. URL-адреса прокси теперь можно разделять запятыми (,) или вертикальной чертой (|). Если за URL-адресом прокси-сервера стоит запятая, команда go будет пробовать только следующий прокси в списке после HTTP-ответа 404 или 410. Если после URL-адреса прокси-сервера следует вертикальная черта, команда go попробует следующий прокси в списке после любой ошибки. Обратите внимание, что значение GOPROXY по умолчанию остается https://proxy.golang.org,direct, которое не возвращается к direct в случае ошибок.

go test

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

Разбор флагов

Исправлены различные проблемы с синтаксическим анализом флагов в go test и go vet. Примечательно, что флаги, указанные в GOFLAGS, обрабатываются более последовательно, а флаг -outputdir теперь интерпретирует относительные пути относительно рабочего каталога команды go (а не рабочего каталога каждого отдельного теста).

Кеш модуля

Местоположение кэша модуля теперь можно задать с помощью переменной среды GOMODCACHE. Значение GOMODCACHE по умолчанию - GOPATH[0]/pkg/mod, расположение кэша модуля до этого изменения.

Теперь доступен обходной путь для ошибок Windows "Access is denied" в командах go, которые обращаются к кэшу модуля, вызванных одновременным сканированием файловой системы внешними программами. Обходной путь не включен по умолчанию, потому что его небезопасно использовать, когда версии Go ниже 1.14.2 и 1.13.10 работают одновременно с одним и тем же кешем модуля. Его можно включить, явно установив переменную среды GODEBUG=modcacheunzipinplace=1.

Vet


Новое предупреждение для string(x)

Инструмент vet теперь предупреждает о преобразованиях формы string(x), где x имеет целочисленный тип, отличный от rune или byte. Опыт работы с Go показал, что многие преобразования этой формы ошибочно предполагают, что string(x) оценивается как строковое представление целого числа x. Фактически он вычисляет строку, содержащую кодировку UTF-8 значения x. Например, string(9786) не оценивается как строка "9786"; а оценивается как строка "\xe2\x98\xba" или "☺️".

Код, который правильно использует string(x), можно переписать в string(rune(x)). Или, в некоторых случаях, правильным решением может быть вызов utf8.EncodeRune(buf, x) с подходящим байтовым срезом buf. Другой код, скорее всего, должен использовать strconv.Itoa или fmt.Sprint.

Эта новая vet проверка включена по умолчанию при использовании go test.

Рассматривается возможность запрета преобразования в будущем выпуске Go. То есть язык изменится, чтобы разрешить string(x) только для целого числа x, если тип x - rune или byte. Такое изменение языка не будет обратно совместимым. Эта vet проверка используется в качестве первого пробного шага к изменению языка.

Новое предупреждение о невозможности преобразования интерфейса

Инструмент vet теперь предупреждает об утверждениях типа от одного типа интерфейса к другому типу интерфейса, когда утверждение типа всегда терпит неудачу. Это произойдет, если оба типа интерфейса реализуют метод с тем же именем, но с другой сигнатурой типа.

Нет причин писать утверждение типа, которое всегда терпит неудачу, поэтому любой код, запускающий эту vet проверку, следует переписать.

Эта новая vet проверка включена по умолчанию при использовании go test.

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


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


воскресенье, 9 августа 2020 г.

Пакет expvar в Golang

Пакет expvar предоставляет стандартизированный интерфейс для общедоступных переменных, таких как счетчики операций на серверах. Он предоставляет эти переменные через HTTP в /debug/vars в формате JSON.

Операции по установке или изменению этих общедоступных переменных являются атомарными.

В дополнение к добавлению обработчика HTTP этот пакет регистрирует следующие переменные:

cmdline   os.Args
memstats  runtime.Memstats

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

import _ "expvar"

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

package main

import (
    _ "expvar"
    "io"
    "log"
    "net/http"
)

func main() {
    helloHandler := func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, "Hello, world!\n")
    }

    http.HandleFunc("/hello", helloHandler)

    log.Fatal(http.ListenAndServe(":8080", nil))
}

При запуске этой программы запускается веб-обработчик и при обращении к http://localhost:8080/hello получаем вывод:

Hello, world!

При обращении к http://localhost:8080/debug/vars получаем примерно следующий вывод:

{
"cmdline": ["C:\\Users\\MyUSER\\AppData\\Local\\Temp\\___go_build_example_go.exe"],
"memstats": {"Alloc":205560,"TotalAlloc":205560,"Sys":6705288,"Lookups":0,"Mallocs":934,"Frees":18,"HeapAlloc":205560,"HeapSys":4063232,"HeapIdle":3162112,"HeapInuse":901120,"HeapReleased":3129344,"HeapObjects":916,"StackInuse":131072,"StackSys":131072,"MSpanInuse":27880,"MSpanSys":32768,"MCacheInuse":6816,"MCacheSys":16384,"BuckHashSys":3675,"GCSys":1407368,"OtherSys":1050789,"NextGC":4473924,"LastGC":0,"PauseTotalNs":0,"PauseNs":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"PauseEnd":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"NumGC":0,"NumForcedGC":0,"GCCPUFraction":0,"EnableGC":true,"DebugGC":false,"BySize":[{"Size":0,"Mallocs":0,"Frees":0},{"Size":8,"Mallocs":15,"Frees":0},{"Size":16,"Mallocs":263,"Frees":0},{"Size":32,"Mallocs":113,"Frees":0},{"Size":48,"Mallocs":275,"Frees":0},{"Size":64,"Mallocs":43,"Frees":0},{"Size":80,"Mallocs":17,"Frees":0},{"Size":96,"Mallocs":12,"Frees":0},{"Size":112,"Mallocs":4,"Frees":0},{"Size":128,"Mallocs":6,"Frees":0},{"Size":144,"Mallocs":1,"Frees":0},{"Size":160,"Mallocs":20,"Frees":0},{"Size":176,"Mallocs":4,"Frees":0},{"Size":192,"Mallocs":0,"Frees":0},{"Size":208,"Mallocs":28,"Frees":0},{"Size":224,"Mallocs":3,"Frees":0},{"Size":240,"Mallocs":4,"Frees":0},{"Size":256,"Mallocs":8,"Frees":0},{"Size":288,"Mallocs":5,"Frees":0},{"Size":320,"Mallocs":3,"Frees":0},{"Size":352,"Mallocs":9,"Frees":0},{"Size":384,"Mallocs":13,"Frees":0},{"Size":416,"Mallocs":6,"Frees":0},{"Size":448,"Mallocs":0,"Frees":0},{"Size":480,"Mallocs":1,"Frees":0},{"Size":512,"Mallocs":6,"Frees":0},{"Size":576,"Mallocs":3,"Frees":0},{"Size":640,"Mallocs":9,"Frees":0},{"Size":704,"Mallocs":2,"Frees":0},{"Size":768,"Mallocs":1,"Frees":0},{"Size":896,"Mallocs":11,"Frees":0},{"Size":1024,"Mallocs":2,"Frees":0},{"Size":1152,"Mallocs":3,"Frees":0},{"Size":1280,"Mallocs":2,"Frees":0},{"Size":1408,"Mallocs":1,"Frees":0},{"Size":1536,"Mallocs":0,"Frees":0},{"Size":1792,"Mallocs":4,"Frees":0},{"Size":2048,"Mallocs":1,"Frees":0},{"Size":2304,"Mallocs":2,"Frees":0},{"Size":2688,"Mallocs":2,"Frees":0},{"Size":3072,"Mallocs":0,"Frees":0},{"Size":3200,"Mallocs":0,"Frees":0},{"Size":3456,"Mallocs":0,"Frees":0},{"Size":4096,"Mallocs":6,"Frees":0},{"Size":4864,"Mallocs":0,"Frees":0},{"Size":5376,"Mallocs":1,"Frees":0},{"Size":6144,"Mallocs":1,"Frees":0},{"Size":6528,"Mallocs":0,"Frees":0},{"Size":6784,"Mallocs":0,"Frees":0},{"Size":6912,"Mallocs":0,"Frees":0},{"Size":8192,"Mallocs":1,"Frees":0},{"Size":9472,"Mallocs":0,"Frees":0},{"Size":9728,"Mallocs":0,"Frees":0},{"Size":10240,"Mallocs":4,"Frees":0},{"Size":10880,"Mallocs":0,"Frees":0},{"Size":12288,"Mallocs":0,"Frees":0},{"Size":13568,"Mallocs":0,"Frees":0},{"Size":14336,"Mallocs":1,"Frees":0},{"Size":16384,"Mallocs":0,"Frees":0},{"Size":18432,"Mallocs":0,"Frees":0},{"Size":19072,"Mallocs":0,"Frees":0}]}
}

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

package main

import (
    "expvar"
    "io"
    "log"
    "net/http"
)

func main() {
    mux := http.NewServeMux()

    helloHandler := func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, "Hello, world!\n")
    }

    mux.HandleFunc("/hello", helloHandler)
    mux.Handle("/stats", expvar.Handler())

    log.Fatal(http.ListenAndServe(":8080", mux))
}


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


пятница, 7 августа 2020 г.

Пакет suffixarray в Golang

Пакет suffixarray реализует поиск подстроки за логарифмическое время, используя массив суффиксов в памяти.

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

// создаем индекс для некоторых данных
index := suffixarray.New(data)

// поиск байтового среза s

// список всех индексов, где s встречается в data
offsets1 := index.Lookup(s, -1) 

// список не более 3 индексов, где s встречается в data
offsets2 := index.Lookup(s, 3)  

Тип Index

Index реализует массив суффиксов для быстрого поиска подстроки.

type Index struct {
    // содержит отфильтрованные или неэкспортированные поля
}

Функция New

func New(data []byte) *Index

New создает новый Index для data. Время создания индекса составляет O(N) для N = len(data).

Метод Bytes

func (x *Index) Bytes() []byte

Bytes возвращает данные, по которым был создан индекс. Его нельзя изменять.

Метод FindAllIndex

func (x *Index) FindAllIndex(r *regexp.Regexp, n int) (result [][]int)

FindAllIndex возвращает отсортированный список неперекрывающихся совпадений регулярного выражения r, где совпадение - это пара индексов, определяющих совпадающий срез x.Bytes(). Если n < 0, все совпадения возвращаются в последовательном порядке. В противном случае возвращается не более n совпадений, и они могут быть непоследовательными. result равен nil, если совпадений нет или если n == 0.

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

package main

import (
    "fmt"
    "index/suffixarray"
    "regexp"
)

func main() {
    index := suffixarray.New([]byte("banana"))
    re, err := regexp.Compile(`an.?`)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    offsets := index.FindAllIndex(re, -1)
    for _, off := range offsets {
        fmt.Println(off)
    }

}

Вывод:

[1 4]

Метод Lookup

func (x *Index) Lookup(s []byte, n int) (result []int)

Lookup возвращает несортированный список из не более n индексов, в которых байтовая строка s встречается в индексированных данных. Если n < 0, возвращаются все вхождения. result равен nil, если s пусто, s не найдено или n == 0. Время поиска равно O(log(N)*len(s) + len(result)), где N - размер проиндексированных данных.

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

package main

import (
    "fmt"
    "index/suffixarray"
)

func main() {
    index := suffixarray.New([]byte("banana"))
    offsets := index.Lookup([]byte("ana"), -1)
    for _, off := range offsets {
        fmt.Println(off)
    }

}

Вывод:

3
1

Метод Read

func (x *Index) Read(r io.Reader) error

Read считывает индекс из r в x; x не должен быть равен nil.

Метод Write

func (x *Index) Write(w io.Writer) error

Write записывает индекс x в w.


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


четверг, 6 августа 2020 г.

Пакет template (html/template) в Golang

Пакет template (html/template) реализует управляемые данными шаблоны для генерации вывода HTML, защищенного от внедрения кода. Он предоставляет тот же интерфейс, что и пакет text/template, и его следует использовать вместо text/template всякий раз, когда выводится HTML.

Этот пакет обертывает пакет text/template, поэтому вы можете использовать его template API интерфейс для безопасного анализа и выполнения HTML-шаблонов.

tmpl, err := template.New("name").Parse(...)
// Проверка ошибок отменена
err = tmpl.Execute(out, data)

В случае успеха tmpl теперь будет безопасным от инъекций. В противном случае err - это ошибка, определенная как ErrorCode.

Шаблоны HTML обрабатывают значения данных как простой текст, который следует закодировать, чтобы их можно было безопасно встроить в документ HTML. Экранирование контекстно, поэтому действия могут появляться в контекстах JavaScript, CSS и URI.

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

Пример

import "text/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")

производит

Hello, <script>alert('you have been pwned')</script>!

но контекстное автоэкранирование в html/template

import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")

производит безопасный, экранированный вывод HTML

Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!

Контексты

Этот пакет понимает HTML, CSS, JavaScript и URI. Он добавляет функции очистки к каждому простому конвейеру действий, поэтому, учитывая отрывок

<a href="/search?q={{.}}">{{.}}</a>

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

<a href="/search?q={{. | urlescaper | attrescaper}}">{{. | htmlescaper}}</a>

где urlescaper, attrescaper и htmlescaper - псевдонимы для внутренних функций экранирования.

Для этих внутренних функций экранирования, если конвейер действий оценивает значение интерфейса nil, он обрабатывается как пустая строка.


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


среда, 5 августа 2020 г.

Пакет ring в Golang

Пакет ring реализует операции с круговыми списками.

Тип Ring

type Ring struct {
     Value interface{} // для использования клиентом; 
                       // нетронутый этой библиотекой
     // содержит отфильтрованные 
     // или неэкспортированные поля
}

Ring - это элемент кругового списка или кольца. У колец нет начала и конца; указатель на любой элемент кольца служит ссылкой на все кольцо. Пустые кольца представлены как nil указатели на Ring. Нулевое значение для Ring - это одноэлементное кольцо с nil Value.

Функция New

func New(n int) *Ring

New создает кольцо из n элементов.

Метод Do

func (r *Ring) Do(f func(interface{}))

Do вызывает функцию f для каждого элемента кольца в прямом порядке. Поведение Do не определено, если f изменяет *r.

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

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    // Создаем новое кольцо размером 5
    r := ring.New(5)

    // Получаем длину кольца
    n := r.Len()

    // Инициализируем кольцо 
    // некоторыми целочисленными значениями
    for i := 0; i < n; i++ {
        r.Value = i
        r = r.Next()
    }

    // Обходим кольцо и распечатываем его содержимое
    r.Do(func(p interface{}) {
        fmt.Println(p.(int))
    })

}

Вывод:

0
1
2
3
4

Метод Len

func (r *Ring) Len() int

Len вычисляет количество элементов в кольце r. По времени выполняется пропорционально количеству элементов.

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

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    // Создаем новое кольцо размером 4
    r := ring.New(4)

    // Печатаем его длину
    fmt.Println(r.Len())

}

Вывод:

4

Метод Link

func (r *Ring) Link(s *Ring) *Ring

Link соединяет кольцо r с кольцом s, так что r.Next() становится s и возвращает исходное значение для r.Next(). r не должно быть пустым.

Если r и s указывают на одно и то же кольцо, их связывание удаляет элементы между r и s из кольца. Удаленные элементы образуют вложенное кольцо, и результатом является ссылка на это вложенное кольцо (если элементы не были удалены, результатом все равно будет исходное значение для r.Next(), а не nil).

Если r и s указывают на разные кольца, их связывание создает одно кольцо с элементами s, вставленными после r. Результат указывает на элемент, следующий за последним элементом s после вставки.

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

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    // Создаем два кольца, r и s, размера 2
    r := ring.New(2)
    s := ring.New(2)

    // Получаем длину кольца
    lr := r.Len()
    ls := s.Len()

    // Инициализируем r нулями
    for i := 0; i < lr; i++ {
        r.Value = 0
        r = r.Next()
    }

    // Инициализируем s единицами
    for j := 0; j < ls; j++ {
        s.Value = 1
        s = s.Next()
    }

    // Связать кольцо r и кольцо s
    rs := r.Link(s)

    // Обходим объединенное кольцо 
    // и распечатываем его содержимое
    rs.Do(func(p interface{}) {
        fmt.Println(p.(int))
    })

}

Вывод:

0
0
1
1

Метод Move

func (r *Ring) Move(n int) *Ring

Move перемещает n % r.Len() элементов назад (n < 0) или вперед (n >= 0) по кольцу и возвращает этот элемент кольца. r не должно быть пустым.

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

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    // Создаем новое кольцо размером 5
    r := ring.New(5)

    // Получаем длину кольца
    n := r.Len()

    // Инициализируем кольцо 
    // некоторыми целочисленными значениями
    for i := 0; i < n; i++ {
        r.Value = i
        r = r.Next()
    }

    // Перемещаем указатель вперед на три шага
    r = r.Move(3)

    // Обходим кольцо и распечатываем его содержимое
    r.Do(func(p interface{}) {
        fmt.Println(p.(int))
    })

}

Вывод:

3
4
0
1
2

Метод Next

func (r *Ring) Next() *Ring

Next возвращает следующий элемент кольца. r не должно быть пустым.

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

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    // Создаем новое кольцо размером 5
    r := ring.New(5)

    // Получаем длину кольца
    n := r.Len()

    // Инициализируем кольцо 
    // некоторыми целочисленными значениями
    for i := 0; i < n; i++ {
        r.Value = i
        r = r.Next()
    }

    // Обходим кольцо и распечатываем его содержимое
    for j := 0; j < n; j++ {
        fmt.Println(r.Value)
        r = r.Next()
    }

}

Вывод:

0
1
2
3
4

Метод Prev

func (r *Ring) Prev() *Ring

Prev возвращает предыдущий элемент кольца. r не должно быть пустым.

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

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    // Создаем новое кольцо размером 5
    r := ring.New(5)

    // Получаем длину кольца
    n := r.Len()

    // Инициализируем кольцо 
    // некоторыми целочисленными значениями
    for i := 0; i < n; i++ {
        r.Value = i
        r = r.Next()
    }

    // Обходим кольцо в обратном направлении 
    // и распечатываем его содержимое
    for j := 0; j < n; j++ {
        fmt.Println(r.Value)
        r = r.Prev()
    }

}

Вывод:

4
3
2
1
0

Метод Unlink

func (r *Ring) Unlink(n int) *Ring

Unlink удаляет n % r.Len() элементов из кольца r, начиная с r.Next(). Если n % r.Len() == 0, r остается неизменным. Результат - удаленное подкольцо. r не должно быть пустым.

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

package main

import (
    "container/ring"
    "fmt"
)

func main() {
    // Создаем новое кольцо размером 6
    r := ring.New(6)

    // Получаем длину кольца
    n := r.Len()

    // Инициализируем кольцо 
    // некоторыми целочисленными значениями
    for i := 0; i < n; i++ {
        r.Value = i
        r = r.Next()
    }

    // Отключаем три элемента от r, начиная с r.Next()
    r.Unlink(3)

    // Обходим оставшееся кольцо
    // и распечатываем его содержимое
    r.Do(func(p interface{}) {
        fmt.Println(p.(int))
    })

}

Вывод:

0
4
5


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


вторник, 4 августа 2020 г.

Пакет heap в Golang

Пакет heap обеспечивает операции кучи (heap) для любого типа, который реализует heap.Interface. Куча - это дерево со свойством того, что каждый узел является узлом с минимальным значением в своем поддереве.

Минимальным элементом в дереве является корень с индексом 0.

Куча - это распространенный способ реализации очереди с приоритетами. Чтобы построить очередь с приоритетами, реализуйте интерфейс Heap с (отрицательным) приоритетом в качестве порядка для метода Less, Push добавляет элементы, а Pop удаляет элемент с наивысшим приоритетом из очереди.

Тип Interface

type Interface interface {
    sort.Interface
    Push(x interface{}) // добавить x как элемент Len()
    Pop() interface{}   // удалить и вернуть элемент Len() - 1.
}

Тип Interface описывает требования к типу с использованием подпрограмм в этом пакете. Любой тип, который реализует это, может использоваться в качестве min-кучи со следующими инвариантами (устанавливаемыми после вызова Init или если данные пусты или отсортированы):

!h.Less(j, i) для 0 <= i < h.Len() и 2*i+1 <= j <= 2*i+2 и j < h.Len() Обратите внимание, что Push и Pop в этом интерфейсе предназначены для вызова реализации пакета heap. Чтобы добавить и удалить вещи из кучи, используйте heap.Push и heap.Pop.

Функция Fix

func Fix(h Interface, i int)

Fix восстанавливает порядок кучи после того, как элемент с индексом i изменил свое значение. Изменение значения элемента по индексу i с последующим вызовом Fix эквивалентно, но менее затратно, чем вызов Remove(h, i), за которым следует Push нового значения. Сложность O(log n), где n = h.Len().

Функция Init

func Init(h Interface)

Init устанавливает инварианты кучи, необходимые для других процедур в этом пакете. Init является идемпотентом по отношению к инвариантам кучи и может вызываться всякий раз, когда инварианты кучи могли быть признаны недействительными. Сложность O(n), где n = h.Len().

Функция Pop

func Pop(h Interface) interface{}

Pop удаляет и возвращает минимальный элемент (согласно Less) из кучи. Сложность O(log n), где n = h.Len(). Pop эквивалентен Remove(h, 0).

Функция Push

func Push(h Interface, x interface{})

Push заталкивает элемент х на кучу. Сложность O(log n), где n = h.Len().

Функция Remove

func Remove(h Interface, i int) interface{}

Remove удаляет и возвращает элемент с индексом i из кучи. Сложность O(log n), где n = h.Len().

Пример целочисленной кучи

Этот пример вставляет несколько int в IntHeap, проверяет минимум и удаляет их в порядке приоритета.

// Этот пример демонстрирует целочисленную кучу, 
// построенную с использованием heap.Interface.
package main

import (
    "container/heap"
    "fmt"
)

// IntHeap это минимальная куча целых чисел.
type IntHeap []int

// Len, Less, Swap для реализации интерфейса sort.Interface
func (h IntHeap) Len() int           { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *IntHeap) Push(x interface{}) {
    // Push и Pop используют приемники указателей, 
    // потому что они изменяют длину среза,
    // не только его содержимое.
    *h = append(*h, x.(int))
}

func (h *IntHeap) Pop() interface{} {
    old := *h
    n := len(old)
    x := old[n-1]
    *h = old[0 : n-1]
    return x
}

// Этот пример вставляет несколько int в IntHeap, 
// проверяет минимум,
// и удаляет их в порядке приоритета.
func main() {
    h := &IntHeap{2, 1, 5}
    heap.Init(h)
    heap.Push(h, 3)
    fmt.Printf("minimum: %d\n", (*h)[0])
    for h.Len() > 0 {
        fmt.Printf("%d ", heap.Pop(h))
    }
}

Вывод:

minimum: 1
1 2 3 5 

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

В этом примере создается PriorityQueue с некоторыми элементами, добавляется и обрабатывается элемент, а затем удаляются элементы в порядке приоритета.

// Этот пример демонстрирует приоритетную очередь, 
// построенную с использованием интерфейса heap.
package main

import (
    "container/heap"
    "fmt"
)

// Item - это то, чем мы управляем в приоритетной очереди.
type Item struct {
    value    string // Значение элемента; произвольное.
    priority int    // Приоритет элемента в очереди.
    // Индекс необходим для обновления 
    // и поддерживается методами heap.Interface.
    index int // Индекс элемента в куче.
}

// PriorityQueue реализует heap.Interface и содержит Items.
type PriorityQueue []*Item

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
    // We want Pop to give us the highest, not lowest, priority so we use greater than here.
    // Мы хотим, чтобы Pop давал нам самый высокий, 
    // а не самый низкий приоритет, 
    // поэтому здесь мы используем оператор больше.
    return pq[i].priority > pq[j].priority
}

func (pq PriorityQueue) Swap(i, j int) {
    pq[i], pq[j] = pq[j], pq[i]
    pq[i].index = i
    pq[j].index = j
}

func (pq *PriorityQueue) Push(x interface{}) {
    n := len(*pq)
    item := x.(*Item)
    item.index = n
    *pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
    old := *pq
    n := len(old)
    item := old[n-1]
    old[n-1] = nil  // избежать утечки памяти
    item.index = -1 // для безопасности
    *pq = old[0 : n-1]
    return item
}

// update изменяет приоритет и значение Item в очереди.
func (pq *PriorityQueue) update(item *Item, value string, priority int) {
    item.value = value
    item.priority = priority
    heap.Fix(pq, item.index)
}

// Этот пример создает PriorityQueue с некоторыми элементами, 
// добавляет и управляет элементом,
// а затем удаляет элементы в порядке приоритета.
func main() {
    // Некоторые элементы и их приоритеты.
    items := map[string]int{
        "banana": 3, "apple": 2, "pear": 4,
    }

    // Создаем очередь с приоритетами, 
    // помещаем в нее элементы и
    // устанавливаем приоритетные инварианты очереди (кучи).
    pq := make(PriorityQueue, len(items))
    i := 0
    for value, priority := range items {
        pq[i] = &Item{
            value:    value,
            priority: priority,
            index:    i,
        }
        i++
    }
    heap.Init(&pq)

    // Вставить новый элемент, 
    // а затем изменить его приоритет.
    item := &Item{
        value:    "orange",
        priority: 1,
    }
    heap.Push(&pq, item)
    pq.update(item, item.value, 5)

    // Вынимаем предметы; 
    // они прибывают в порядке убывания приоритета.
    for pq.Len() > 0 {
        item := heap.Pop(&pq).(*Item)
        fmt.Printf("%.2d:%s ", item.priority, item.value)
    }
}

Вывод:

05:orange 04:pear 03:banana 02:apple 


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


купить игрушку gopher

воскресенье, 2 августа 2020 г.

Пакет list - двусвязный список в Golang

Пакет list реализует двусвязный список.

Чтобы перебрать список (где l - *List):

for e := l.Front(); e != nil; e = e.Next() {
    // делаем что-либо с e.Value
}

Пример двусвязного списка в Golang

package main

import (
    "container/list"
    "fmt"
)

func main() {
    // Создаем новый список 
    // и помещаем в него несколько чисел.
    l := list.New()
    e4 := l.PushBack(4)
    e1 := l.PushFront(1)
    l.InsertBefore(3, e4)
    l.InsertAfter(2, e1)    
    fmt.Printf("Длина списка %v\n", l.Len())

    fmt.Println("Итерируем по списку с начала.")
    for e := l.Front(); e != nil; e = e.Next() {
        fmt.Println(e.Value)
    }   

    fmt.Println("Итерируем по списку с конца.")
    for e := l.Back(); e != nil; e = e.Prev() {
        fmt.Println(e.Value)
    }

}

Вывод:

Длина списка 4
Итерируем по списку с начала.
1
2
3
4
Итерируем по списку с конца.
4
3
2
1


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


Пакет time в Golang, тип Timer

type Timer struct {
    C <-chan Time
    // содержит отфильтрованные или неэкспортированные поля
}

Тип Timer представляет одно событие. Когда истекает Timer, текущее время будет отправлено на C, если Timer не был создан AfterFunc. Timer должен быть создан с NewTimer или AfterFunc.

Функция AfterFunc

func AfterFunc(d Duration, f func()) *Timer

AfterFunc ожидает истечения продолжительности d и затем вызывает f в своей собственной goroutine. Он возвращает Timer, который можно использовать для отмены вызова, используя метод Stop.

Функция NewTimer

func NewTimer(d Duration) *Timer

NewTimer создает новый Timer, который будет отправлять текущее время на своем канале, по крайней мере, после продолжительности d.

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

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("Создаем таймер")
    timer := time.NewTimer(1 * time.Second)
    
    fmt.Println("Ждем таймер")
    <-timer.C

    fmt.Println("Таймер истек")
}

Метод Reset

func (t *Timer) Reset(d Duration) bool

Reset изменяет таймер на истечение после срока действия d. Он возвращает true, если таймер был активен, false, если таймер истек или был остановлен.

Reset должен вызываться только на остановленных или истекших таймерах с опустошенными каналами. Если программа уже получила значение от t.C, таймер, как известно, истек, и канал опустошен, поэтому t.Reset можно использовать напрямую. Однако, если программа еще не получила значение от t.C, таймер должен быть остановлен и - если Stop сообщает, что истек таймер до его остановки - канал явно опустошен:

if !t.Stop() {
    <-t.C
}
t.Reset(d)

Это не должно быть сделано конкурентно с другими приемами от канала Timer.

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

Метод Stop

func (t *Timer) Stop() bool

Stop предотвращает срабатывание Timer. Он возвращает true, если вызов останавливает таймер, false, если таймер уже истек или был остановлен. Stop не закрывает канал, чтобы предотвратить неправильное чтение с канала.

Чтобы убедиться, что канал пуст после вызова Stop, проверьте возвращаемое значение и опустошите канал. Например, если программа еще не получила от t.C:

if !t.Stop() {
    <-t.C
}

Это не может быть сделано одновременно с другими приемами из канала Timer или другими вызовами метода Stop таймера.

Для таймера, созданного с помощью AfterFunc(d, f), если t.Stop возвращает false, то время таймера уже истекло, и функция f была запущена в своей собственной goroutine; Stop не ждет завершения f перед возвратом. Если вызывающий должен знать, завершено ли f, он должен явно координировать с f.


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


суббота, 1 августа 2020 г.

Пакет time в Golang, тип Time, методы Sub, Truncate, Round

Метод Sub

func (t Time) Sub(u Time) Duration

Sub возвращает продолжительность t-u. Если результат превышает максимальное (или минимальное) значение, которое может быть сохранено в Duration, будет возвращена максимальная (или минимальная) продолжительность. Чтобы вычислить t-d для продолжительности d, используйте t.Add(-d).

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

package main

import (
    "fmt"
    "time"
)

func main() {
    start := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
    end := time.Date(2000, 1, 1, 12, 0, 0, 0, time.UTC)

    difference := end.Sub(start)
    fmt.Printf("difference = %v\n", difference)

}

Вывод:

difference = 12h0m0s

Метод Truncate

func (t Time) Truncate(d Duration) Time

Truncate возвращает результат округления t до значения, кратного d (начиная с нулевого времени). Если d <= 0, Truncate возвращает t без любых монотонных показаний часов, но в остальном без изменений.

Truncate действует над временем как абсолютной продолжительностью с нулевого времени; он не действует в форме представления времени. Таким образом, Truncate(Hour) может возвращать время с ненулевой минутой, в зависимости от Location времени.

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

package main

import (
    "fmt"
    "time"
)

func main() {
    t, _ := time.Parse("2006 Jan 02 15:04:05", "2012 Dec 07 12:15:30.918273645")
    trunc := []time.Duration{
        time.Nanosecond,
        time.Microsecond,
        time.Millisecond,
        time.Second,
        2 * time.Second,
        time.Minute,
        10 * time.Minute,
    }

    for _, d := range trunc {
        fmt.Printf("t.Truncate(%5s) = %s\n", d, 
                   t.Truncate(d).Format("15:04:05.999999999"))
    }
    // Чтобы округлить до последней полуночи 
    // в местном часовом поясе, создаем новую Date.
    midnight := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
    _ = midnight

}

Вывод:

t.Truncate(  1ns) = 12:15:30.918273645
t.Truncate(  1µs) = 12:15:30.918273
t.Truncate(  1ms) = 12:15:30.918
t.Truncate(   1s) = 12:15:30
t.Truncate(   2s) = 12:15:30
t.Truncate( 1m0s) = 12:15:00
t.Truncate(10m0s) = 12:10:00

Метод Round

func (t Time) Round(d Duration) Time

Round возвращает результат округления t до ближайшего кратного d (начиная с нулевого времени). Поведение при округлении для значений на полпути заключается в округлении. Если d <= 0, Round возвращает t без любых монотонных показаний часов, но в остальном без изменений.

Round действует над временем как абсолютной продолжительностью с нулевого времени; он не действует в форме представления времени. Таким образом, Round(Hour) может возвращать время с ненулевой минутой, в зависимости от Location времени.

Отличие от метода Truncate заключается в том, что Truncate возвращает результат округления t до кратного d, а Round возвращает результат округления t до ближайшего кратного d.

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

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Date(0, 0, 0, 12, 15, 30, 918273645, time.UTC)
    round := []time.Duration{
        time.Nanosecond,
        time.Microsecond,
        time.Millisecond,
        time.Second,
        2 * time.Second,
        time.Minute,
        10 * time.Minute,
        time.Hour,
    }

    for _, d := range round {
        fmt.Printf("t.Round(%6s) = %s\n", d, t.Round(d).Format("15:04:05.999999999"))
    }
}

Вывод:

t.Round(   1ns) = 12:15:30.918273645
t.Round(   1µs) = 12:15:30.918274
t.Round(   1ms) = 12:15:30.918
t.Round(    1s) = 12:15:31
t.Round(    2s) = 12:15:30
t.Round(  1m0s) = 12:16:00
t.Round( 10m0s) = 12:20:00
t.Round(1h0m0s) = 12:00:00


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