# Полезные функции | Max Wiki Site
Перехват Ctrl+C Более простой вариант Как правильно реализовать Singletone Ожидание нажатия Enter в консоли Логирование из тестов Создание собственного типа аргумента командной строки Удаление элемента из slice Подключение к Microsoft IIS по SSL Вычисление абсолютного значения целых чисел Перехват Ctrl+C Информация взята из блога Mat Ryer. func main() { ctx := context.Background() // trap Ctrl#C and call cancel on the context ctx, cancel := context.WithCancel(ctx) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) defer func() { signal.Stop(c) cancel() }() go func() { select { case [cut: 865 characters, first 597 kept]

# Полезные функции

## Перехват Ctrl+C

Информация взята из блога Mat Ryer
.

    func main() {
        ctx := context.Background()

        // trap Ctrl#C and call cancel on the context
        ctx, cancel := context.WithCancel(ctx)
        c := make(chan os.Signal, 1)
        signal.Notify(c, os.Interrupt)
        defer func() {
            signal.Stop(c)
            cancel()
        }()
        go func() {
            select {
            case <-c:
                cancel()
            case <-ctx.Done():
            }
        }()

        doSomethingAwesome(ctx)
    }

### Более простой вариант

    func main() {
        c := make(chan os.Signal, 1)
        signal.Notify(c, os.Interrupt)
    // Wait for Ctrl#C
        <-c
    }

## Как правильно реализовать Singletone

Вариант взят отсюда singleton-pattern-in-go
.

    package singleton

    import (
        "sync"
    )

    type singleton struct {
    }

    var instance *singleton
    var once sync.Once

    func GetInstance() *singleton {
        once.Do(func() {
            instance = &singleton{}
        })
        return instance
    }

## Ожидание нажатия Enter в консоли

    func main() {
        fmt.Println("Press Enter...")
        bufio.NewReader(os.Stdin).ReadLine()
        fmt.Println("Exit")
    }

## Логирование из тестов

Чтобы вывести произвольную информацию из теста Go можно использовать метод `testing.T.Logf()`. Чтобы информация из него выводилась в консоль при запуске теста необходимо запускать тесты с ключом -v:

    go test -v

## Создание собственного типа аргумента командной строки

Допустим, хотим заполнить тип `time.Time` на основании значения, принятого из командной строки. Чтобы создать свой флаг необходимо имплементировать интерфейс `time.Value` имеющий следующий вид:

    type Value interface {
            String() string
            Set(string) error
    }

Соответственно, нужно имплементировать эти два метода на нашей структуре. Создаём следующую структуру.

    // DateTimeFlag представляет аргумент командной строки для даты.
    type DateTimeFlag struct {
        time.Time
    }

    func (dtf *DateTimeFlag) String() string {
        return fmt.Sprint(*dtf)
    }

    // Set вызывается в момент разбора аргумента командной строки.
    func (dtf *DateTimeFlag) Set(value string) (err error) {
        dtf.Time, err = time.Parse("2006.01.02", value)
        return
    }

В данном конкретно случае, так как у нас в структуре анонимный тип `time.Time` уже имплементирует метод `String()`, то его можно пропустить.

Чтобы добавить в свою программу возможность использования данного типа делаем следующее:

- Объявить переменные созданного типа
- Добавить в секцию `init()` регистрацию этих переменных в качестве флагов.

    var date DateTimeFlag

    func init() {
        flag.Var(&date, "date", "date from command line")
    }

Дальнейшее использование как обычно:

    flag.Parse()

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

    // Правильно
    fmt.Println(date)
    // Неправильно
    fmt.Println(*date)

## Удаление элемента из slice

Информация взята из SliceTricks
.

    a = append(a[:i], a[i+1:]...)

## Подключение к Microsoft IIS по SSL

В случае ошибки подключения по ssl `local error: tls: no renegotiation`. Необходимо настроить транспорт следующим образом:

    transport := &http.Transport{
            TLSClientConfig: &tls.Config{
                Certificates: []tls.Certificate{cert},
                RootCAs:       caCertPool, // Если надо. Инициализацию смотри ниже.
                Renegotiation: tls.RenegotiateFreelyAsClient, // Собственно этот параметр и включает совместимость.
            }}

И затем использовать его в HTTP-клиенте:

    client := http.Client{Transport: transport}

При этом загрузка корневых сертификатов (при необходимости) происходит следующим образом:

    caCert, err := ioutil.ReadFile("<path_to_ca.pem>")
    if err != nil {
        log.Fatalf("Error read ca certs: %v", err)
    }
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)

## Вычисление абсолютного значения целых чисел

    func absInt32(n int32) int32 {
        y := n >> 31
        return (n ^ y) - y
    }

    func absInt64(n int64) int64 {
        y := n >> 63
        return (n ^ y) - y
    }