Pull to refresh
4
0
Владислав @ghostiam

На Go писатель, серверов пинатель.

Send message

Для работы с бд есть тип в стандартной библиотеке

https://pkg.go.dev/database/sql#Null

var s Null[string]
err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
...
if s.Valid {
   // use s.V
} else {
   // NULL value
}

Скрытый текст

Подобный подход с опциями используется в GRPC и Goland хорошо справляется(всё из списка на скрине это валидные опции кроме tabnine, это AI), особенно если использовать комбинацию Shift+Ctrl+Space , чтобы автодополнение учитывало тип.

Сейчас набирает популярность Templ, позволяет писать шаблон почти как код на go и преобразуется в go код после генерации(с нормальными типами, а не просто map), то есть никакого парсинга шаблонов в рантайме.
Мне понравился, но поддержка редакторов пока скудная.

Спасибо за статью.

Но разве UseCase должен преобразовать Markdown в HTML?

Что если нам понадобится, в будущем, REST API для блога или мы захотим читать блог через терминал с диска со специальным форматированием для него?

Думаю таким должен заниматься UI слой, получая только модель с данными.

Из бесплатных: ImHex (кроссплатформенный и open-source), шаблоны описываются си-подобным языком.
Из платных: Synalyze It! (MacOS) и он же под Windows - Hexinator, тут уже шаблоны настраиваются через GUI.

Судя по ответу автора в дискорде, там не всё так честно
https://discord.com/channels/1055397662976905229/1106944669474099294

Скорее всего, он использует сайты, как gpt4free, только мимикрирует как реверс прокси и из за этого его можно спокойно использовать во многих программах и плагинах.

Сири спрашивает, что вы имеете ввиду, сегодня (такая дата) или завтра (такая дата)

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

Так же, IDE спокойно подсвечивает имена полей, если их не указать явно, поэтому не вижу никаких проблем.

Претензия высосана из пальца, так как го выдаёт ошибку если не все поля инициализированы в структуре, но он сам указал, чтобы остальные поля были default, указав ключ-значение.

Этот код не скомпилируется:

package main

import "log"

type Params struct {
	a int32
	b int32
}

func work(p Params) {
	log.Printf("Working with a=%v, b=%v", p.a, p.b)
}

func main() {
	work(Params{
		47,
  }) // <- Error: too few values in struct literal
}

Можно забекапить с помощью этого скрипта https://github.com/josegonzalez/python-github-backup

Бэкапит не только репозитории с issue/pr, но и wiki, gists, и может бекапить ещё и репозитории помеченные stars.

(упомяну @krak, чтобы 2 комментария не писать)

Так же, из опыта: в соло, игру можно пройти менее чем за 8 часов.
Я выбивал ачивку «Недотёпам здесь не место», получилось с первого раза за ~7:23 с минимальной эволюцией жуков(чтобы не тратить силы на оборону), но получится такой говнокодзавод с лапшеобразными конвейерами и трубами, что потом его только сжечь…
Пруф, я нанят?)
У меня в сети напряжение гуляет от 218 до 244 Вольт (в зависимости от времени суток).
Желающие могут посмотреть на снапшот мониторинга из графаны, замеров напряжения на UPS за неделю.
Снапшот тут.

500мб это компилятор го, сам образ для работы приложения не нужен.
С помощью многоэтапной сборки можно запустить go приложение в докере вообще без базового докер образа, просто from scratch.

А для чего такие сложности с настройкой? Для этих целей существует docker-machine с драйвером generic, который настроит сервер и клиент одной командой:
docker-machine create -d generic --generic-ip-address {ip-address} {docker-vm-name}

На сервере даже докер руками ставить не надо, docker-machine сам всё установит, нужен докер только на клиенте.

Как я помню, докер из brew ставится без зависимостей, только сам бинарь, что позволяет, опять же, убрать ручной труд.

Получается статью можно было сжать до нескольких строк:
Покупаем VPS
Устанавливаем докер на Мак:
brew install docker docker-machine

и запускаем настройку связи с сервером
docker-machine create -d generic --generic-ip-address {ip-address} {docker-vm-name}


P.S. Если docker-vm-name назвать как default то это машина будет использоваться по умолчанию.
Ошибка в го, это любая структура, у которой есть метод `Error() string`
«Сложные» ошибки есть в стандартных пакетах, а в своих проектах обычно хватает оборачивания ошибки в свою ошибку с описанием, благо в Go1.13 завезли это в стандартную библиотеку Работа с ошибками в Go 1.13
image

В комментариях к оригиналу дали ссылку на готовое онлайн приложение, которое создаёт графы
https://anvaka.github.io/vs/?query=habr

Как я понимаю, это что-то типо итога раздела, там ссылаются на ту же мысль, что с глобальной переменной было плохо, а без неё мы на вопросы
Вы можете изолированно тестировать её? Можете тестировать параллельно? Можете использовать одновременно несколько экземпляров?

можем ответить «Да», просто такое вполне может быть и в реальном проекте.

Например, далеко ходить не нужно, возьмём стандартную библиотеку net/http, и стандартный роутер для http сервера http.ServeMux.
Сделаем простой сервер (обработку ошибок опустим)
Код
package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})
	go http.ListenAndServe(":3000", nil)
	go http.ListenAndServe(":3001", nil)

	select {}
}


В примере выше, зайдя на http://localhost:3000/hello и на http://localhost:3001/hello мы увидим одно и то же, так как http.HandleFunc по факту вызывает метод у глобальной переменной, а http.ListenAndServe при передаче вторым параметром nil её использует.
Хорошо ли это? Для прототипов, возможно, но это неявная «магия» и на вопросы выше уже не получится так однозначно ответить.
Но если мы сделаем тот же сервер с созданием нового роутера и передадим его явно, проблемы тут же исчезают:
Код
package main

import (
	"net/http"
)

func main() {
	r1 := http.NewServeMux()
	r1.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world 3000"))
	})
	
	r2:= http.NewServeMux()
	r2.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world 3001"))
	})
	
	go http.ListenAndServe(":3000", r1)
	go http.ListenAndServe(":3001", r2)

	select {}
}


И такое не редко встречается, но данный пример не так опасен, так как в данном случае мы смогли создать новый экземпляр который не повлияет на остальные, но ведь существуют библиотеки, которые хочется выполнять в разных горутинах или параллельно, но не получается, так как у неё объявлена важная глобальная переменная, которая влияет на все остальные вызовы этой библиотеки.
В статье речь была о проблеме с глобальной переменной count, а в примере с объектом всё хорошо, пока вы не вызываете метод Increment в разных горутинах.
Но и это починить не сильно сложно, просто добавь воды мьютекс или для счётчика можно использовать atomic (пришлось заменить int на int64, так как atomic умеет работать только с int32/uint32 и int64/uint64 указанными явно):
package counter

import (
	"sync"
	"sync/atomic"
)

type Counter struct {
	count int64
	mx    sync.Mutex
}

func (c *Counter) Increment(n int64) int64 {
	c.mx.Lock()
	defer c.mx.Unlock()

	c.count += n
	return c.count
}
func (c *Counter) IncrementAtomic(n int64) int64 {
	atomic.AddInt64(&c.count, n) 
	return atomic.LoadInt64(&c.count)
}

Для этого они просят указывать email при получении сертификата.
Мне недавно пришло письмо с указанием доменов, где находится старый certbot с сообщением, что надо бы обновить, так как старое апи будет отключено.
1

Information

Rating
6,226-th
Date of birth
Registered
Activity