type Response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
}
В данном случае это ``json:"page"`` и ``json:"fruits"``.
Но иногда, вместо JSON используются другие стандарты, BSON и др. Так вот, что делать в случае других стандартов?
type Response2 struct {
Page int `json:"page" yaml:"page" validation:"min:1,max:10"`
Fruits []string `json:"fruits" yaml:"fruits,omitempty" validation:"nonempty"`
}
r := &Response2{}
json.Read("file.json", r)
validator.Validate(r)
yaml.Write("file.yaml", r)
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤6🔥6
Вдобавок к этому ISO 8601 не всегда соблюдается в сторонних API, что создает неприятности.
Если коротко, то решение проблемы заключается в использовании кастомных типов и функций
Unmarshaler
для парсинга нестандартных дат.Этот подход также может быть использован для успешного парсинга любого нестандартного контента, кстати.
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥4❤3
При этом, если функция будет работать больше указанного количества секунд, нужно прервать ее выполнение.
Таким образом нужно прервать выполнение этой функции
fun()
ниже, что можно сделать?
package main
import (
"fmt"
"sync"
)
func FibonacciRecursion(n int) int {
if n <= 1 {
return n
}
return FibonacciRecursion(n-1) + FibonacciRecursion(n-2)
}
func f(i int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println(FibonacciRecursion(45 + i))
}
func fun() {
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
go f(i, &wg)
wg.Add(1)
}
wg.Wait()
println("Function ended")
}
func main() {
fun()
}
С помощью
context
код выше можно переписать так:
package main
import (
"context"
"fmt"
"sync"
"time"
)
func main() {
timeLimit := time.Second * 10
ctx, cancel := context.WithTimeout(context.Background(), timeLimit)
defer cancel()
fun(ctx)
}
func isDone(ctx context.Context) bool {
select {
case <-ctx.Done():
return true
default:
return false
}
}
func FibonacciRecursion(ctx context.Context, n int) int {
if n <= 1 || isDone(ctx) {
return n
}
return FibonacciRecursion(ctx, n-1) + FibonacciRecursion(ctx, n-2)
}
func f(ctx context.Context, i int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println(FibonacciRecursion(ctx, 45+i))
}
func fun(ctx context.Context) {
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go f(ctx, i, &wg)
}
wg.Wait()
println("Function ended")
}
Такие вот дела
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍34🔥7❤5🤬1
go.mongodb.org/mongo-driver/mongo
?На локальном компьютере при отключении Mongo приложение в течение 30 секунд висит (видимо пытается подключиться).
Это время — оно задается в настройках клиента библиотеки или в самой Mongo или от чего еще зависит? Mongo поднята в контейнере, код подключения такой:
ctx, _ := context.WithTimeout(context.Background(), timeoutSecond*time.Second)
client, err := mongo.Connect(ctx, options.Client().ApplyURI(connString))
Сам запрос вот:
err := mr.client.Database(mr.dbName).Collection(mr.collName).FindOne(ctx, filter).Decode(&p)
context.WithTimeout
или context.WithCancel(ctx)
. Помимо этого, у вас имеется возможность настроить клиент к базе.У клиента есть ряд параметров с таймаутами, одни для выполнения одной операции, другие отвечают за время подключения к серверу (можно сказать время отклика сервера).
go channel
), который ожидает выполнения функции, либо завершения контекста, истечения timeout
этого запроса.select {
case <-ctx.Done():
return nil, ctx.Err()
case <-selectionState.timeoutChan:
return nil, wrapServerSelectionError(ErrServerSelectionTimeout, t)
case current = <-subscriptionCh:
}
срабатывает
<-selectionState.timeoutChan
, по умолчанию его значение 30 секундclient, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"),
options.Client().SetConnectTimeout(time.Second * myTimeout),
options.Client().SetServerSelectionTimeout(time.Second * myServerTimeout))
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥4❤2
Мощная шпаргалка по Go, которая покрывает практически все темы
Если пролистать хотя бы по диагонали, есть отличный от нуля шанс пройти собеседование и получить оффер)
Что внутри?
├╼
Компилятор├╼
Пакеты├╼
Функции├╼
Управление памятью├╼
Операторы├╼
Управляющие структуры├╼
Объектноориентированность├╼
Интерфейсы├╼
Обработка ошибок├╼
Горутины (Goroutine)├╼
Проверка управления памятью├╼
Reflect ├╼
Добавление кода C├╼
GUI╰╼
Распределенные системы@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍30🔥8❤5
При работе с базой данных миграция схемы является одной из важных задач, которую нам часто приходится выполнять на протяжении всего жизненного цикла приложения, чтобы адаптироваться к новым бизнес-требованиям.
И в этой статье речь пойдёт о том, как написать и запустить миграцию схемы базы данных в Golang, используя библиотеку
golang-migrate
, уверен, будет полезно@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍8🔥5🤔2
Держите полезные библиотеки для реализации схем аутентификации. Вы готовы? Их немало)
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍30🔥7❤4🤬1
ssl/tls
сертификатов. В коде есть фрагменты передачи данных из форм такого типаhttps://localhost:8080/?param1=value
Сейчас, без использования шифрования транспорта, можно получить значение
param1
такr.FormValue("param1")
Вопрос: если начать шифровать транспорт, сами данные останутся незашифрованны ведь? Или придётся изменить способ получения параметров из запроса и сперва эти параметры расшифровать?
package main
import (
"fmt"
"log"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte(fmt.Sprintf("param1=%s", r.FormValue("param1"))))
}
func main() {
http.HandleFunc("/", handler)
http.NewServeMux()
err := http.ListenAndServeTLS(":8080", "server.crt", "server.key", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
А вот команда генерации сертификатов:
openssl req -x509 -nodes -newkey rsa:2048 -keyout server.key -out server.crt -days 3650
Такие дела
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23😁6❤4🥰2
Самый простой способ писать хороший код заключается в том, чтобы не употреблять в своих программах «антипаттерны». Собственно, об этом и идёт речь в этой полезной статье
А вот некоторые из обсуждаемых антипаттернов:
// Не рекомендовано
type unexportedType string
func ExportedFunc() unexportedType {
return unexportedType("some string")
}
// Рекомендовано
type ExportedType string
func ExportedFunc() ExportedType {
return ExportedType("some string")
}
// Не рекомендовано
for _ = range sequence
{
run()
}
x, _ := someMap[key]
_ = <-ch
// Рекомендовано
for range something
{
run()
}
x := someMap[key]
<-ch
return
в функциях// Бесполезное выражение return, не рекомендовано
func alwaysPrintFoofoo() {
fmt.Println("foofoo")
return
}
// Рекомендовано
func alwaysPrintFoo() {
fmt.Println("foofoo")
}
break
в выражениях switch
// Не рекомендовано
switch s {
case 1:
fmt.Println("case one")
break
case 2:
fmt.Println("case two")
}
// Рекомендовано
switch s {
case 1:
fmt.Println("case one")
case 2:
fmt.Println("case two")
}
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍30❤8🔥5😢1
ssh
, но через go get
/ go install
происходит ошибка:go: unrecognized import path "private.gitlab.ru/repositoryName": https fetch: Get "https://private.gitlab.ru/repositoryName?go-get=1": dial tcp 255.255.255.255:443(левый IP адрес): i/o timeout
Попытки установить хост данного репозитория себе в переменные
GONOPROXY
/ GOPRIVATE
/ GONOSUMDB
не помогли, ошибка остаётся той же.git config --global url."[email protected]".insteadOf "https://private.gitlab.ru"
git config --global url."https://${user}:${personal_access_token}@private.gitlab.ru".insteadOf"https://private.gitlab.ru"
После этого
go get
/ go install
будут работать с приватными репозиториями.@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43❤8🔥6
This media is not supported in your browser
VIEW IN TELEGRAM
О чём речь в статье?
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25❤7🔥3
1
сделаем это пост полезным - выкладывайте в комментариях свои проекты, код, наработки, лучшие попадут в подборку.
сделаем это пост полезным - выкладывайте в комментариях свои проекты, код, наработки, лучшие попадут в подборку.
❤12👍3🔥1
Пакет Go Mongo, поддерживающий операции по работе с документами и эффективным компоновщиком данных BSON с использованием различных типов данных.
BSON - бинарная форма представления простых структур данных и ассоциативных массивов (которые в контексте обмена называют объектами или документами)
go get github.com/chenmingyong0423/go-mongox
#golang #MongoDB
▪ Github
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍6🔥2
go-daemon
:какой лимит по умолчанию на количество открытых дескрипторов файла в Go? Как его менять? И есть ли общепринятые рекомендации по их количеству?
ulimit -a
и ulimit -aH
в shell'е перед запуском вашего демона. Это быстро покажет текущие "мягкие" и (второй вызов) "жесткие" ограничения. При помощи ulimit
можно открутить мягкие ограничения до пределов жестких. Следует понимать, что ulimit
меняет только текущие лимиты, для шелла и всех программ, запущенных в этом шелле, поэтому после завершения сессии или даже в другом окне терминала значения останутся прежними./etc/security/limits.conf
и каталог /etc/security/limits.d/
, ограничение называется nofile
. Редактировать (а, иногда, и смотреть) эти файлы может только суперпользователь ("root"). Там задаются ограничения на отдельных пользователей или группы, применяемые на всю сессию данного пользователя, или всех пользователей определенной группы.sysctl
- это fs.nr_open
:/sbin/sysctl -n fs.nr_open
ему же соответствует файл
/proc/sys/fs/nr_open
getrlimit
/setrlimit
, которые можно звать из Go, используя FFI (примеры можно посмотреть здесь)@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤3🔥3
Основная идея — отделить интерфейс хранилища данных от его реализации. Тогда мы можем использовать различные реализации хранилища, обладающие одним интерфейсом
entity
/user
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🤔5❤4🔥3
Основная цель этого шаблона, кроме обучения — это снизить время на прототипирование небольших серверных задач на Go.
Шаблон включает в себя:
На изображении — UML-диаграмма последовательности запуска и остановки сервера
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥31👍12❤6
./goprogram
1 29.06.2099 14:10
./goprogram
2 29.06.2099 14:12
./goprogram
3 29.06.2099 15:10
./goprogram
4 30.06.2099 14:10
При этом ни каких дополнительных файлов или записей не должно создаваться.
На Purebasic довольно просто такое реализовать:
• Скомпилированный бинарный файл создаёт свою копию.
• Записывает в конец файла число.
• Замещает оригинал изменённой копией.
• При повторном запуске выводит записанное число.
• Можно пример такой реализации на Go?
type persistent struct {
Magic [8]byte
Content int64
}
var p = persistent{
Magic: [8]byte{0xBA, 0xDD, 0xFA, 0xCE, 0xBE, 0xEF, 0xCA, 0xCE},
Content: 0,
}
func main() {
fmt.Println(p.Content)
const size = int(unsafe.Sizeof(p))
currentBuf := bytes.NewBuffer(make([]byte, 0, size))
err := binary.Write(currentBuf, binary.LittleEndian, p)
newP := p
newP.Content++
newBuf := bytes.NewBuffer(make([]byte, 0, size))
err = binary.Write(newBuf, binary.LittleEndian, newP)
currentBytes, newBytes := currentBuf.Bytes(), newBuf.Bytes()
self, err := os.OpenFile(os.Args[0], os.O_RDONLY, 0755)
selfBytes, err := ioutil.ReadAll(self)
i := bytes.Index(selfBytes, currentBytes)
copy(selfBytes[i:i+size], newBytes)
newSelf, err := ioutil.TempFile("", "selfmodifying")
_, err = newSelf.Write(selfBytes)
err = os.Rename(newSelf.Name(), self.Name())
err = os.Chmod(self.Name(), 0755)
}
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤4🤬4🔥3