В одном из недавних постов я писал, что люди требуют крови!: https://yangx.top/golang_for_two/16
CloudFlare написал long read на эту тему, что пошло не так -> https://new.blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019
Но самое интересно, там есть Gif в которой тестируют RegExp и Go комюнити в лице Nate Fintch прикинул, что можно написать так:
// Equivalent normal code is worst case len(s)+1 steps:
CloudFlare написал long read на эту тему, что пошло не так -> https://new.blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019
Но самое интересно, там есть Gif в которой тестируют RegExp и Go комюнити в лице Nate Fintch прикинул, что можно написать так:
// Equivalent normal code is worst case len(s)+1 steps:
if !strings.HasSuffix(s, ";") {
return false
}
if !strings.Contains(s, "=") {
return false
}
Telegram
Go на двоих
COME ON SHOW US THE REGULAR EXPRESSION
или как Cloudflare обещает показать регулярное выражение ...
https://blog.cloudflare.com/cloudflare-outage/
или как Cloudflare обещает показать регулярное выражение ...
https://blog.cloudflare.com/cloudflare-outage/
В Go есть репозиторий "golang/proposal" который описывает процесс внесение изменений в язык. Так вот, Russ и ко. смекнули, (вероятно) после недавних зафейлиных предложений, что нужно что-то менять.
Мысли Russ'а можно прочитать тут, обещает опубликовать продолжение через пару дней🍿
Мысли Russ'а можно прочитать тут, обещает опубликовать продолжение через пару дней🍿
💡Рубрика интересный факт:
Кто из вас слышал, что в Go до версии 1.0 был debugger под названием, барабанная дробь: OGLE.
Те задумка была такая:
Кто из вас слышал, что в Go до версии 1.0 был debugger под названием, барабанная дробь: OGLE.
Те задумка была такая:
> go ogle main.goК сожалению, дебаггер не был готов к релизу go1.0 и его дропнули💩
Note #7 О стилистике Decode//UnMarshal 🐣
Недавно в твиттере возник вопрос, что лучше писать:
Если такого типа нет, оба варианта подойдут и как все знают на вкус и цвет фломастеры разные, хотя второй вариант более универсальный кмк.
Пару ссылок:
- Интересный gist о том как можно приводить типы между источниками
- Дока о том, что Decode - это обычно выражает Unmarshal BinaryUnmarshaler
Недавно в твиттере возник вопрос, что лучше писать:
// Option AИли так:
var v T
v.Decode(someData)
Option BНа самом деле все зависит от контекста, а именно вариант В) или использование метода вместо функции - позволяет типам удовлетворять интерфейсам, т.е другими словами, если у вас есть где-то
func (t *T) Decode(data []byte) {
// decode data into *t
}
type Decoder interface{ Decode([]byte) error }
,Если такого типа нет, оба варианта подойдут и как все знают на вкус и цвет фломастеры разные, хотя второй вариант более универсальный кмк.
Пару ссылок:
- Интересный gist о том как можно приводить типы между источниками
- Дока о том, что Decode - это обычно выражает Unmarshal BinaryUnmarshaler
Note #8 Ast T-shirt👕
Допустим вы решили себе напечатать футболку с куском кода который на Go, но hello-world это скучно. Вот вам идея, взять кусок синтаксического дерева из if err != nil. А если серьезно, то всегда интересно посмотреть - во что превратится ваша программа, когда компилятор ее парсит и строит ситаксическое дерево.
В общем получится что-то типа такого:
Если чуток почистить, то можно и на чашку вместить:
Ссылки:
- поиграться
- почитать
Допустим вы решили себе напечатать футболку с куском кода который на Go, но hello-world это скучно. Вот вам идея, взять кусок синтаксического дерева из if err != nil. А если серьезно, то всегда интересно посмотреть - во что превратится ваша программа, когда компилятор ее парсит и строит ситаксическое дерево.
В общем получится что-то типа такого:
55 . 1: *ast.IfStmt {
56 . . If: 5:2
57 . . Cond: *ast.BinaryExpr {
58 . . . X: *ast.Ident {
59 . . . . NamePos: 5:5
60 . . . . Name: "err"
61 . . . . Obj: *(obj @ 38)
62 . . . }
63 . . . OpPos: 5:9
64 . . . Op: !=
65 . . . Y: *ast.Ident {
66 . . . . NamePos: 5:12
67 . . . . Name: "nil"
68 . . . }
69 . . }
Если чуток почистить, то можно и на чашку вместить:
&ast.IfStmt{
Cond: &ast.BinaryExpr{
X: &ast.Ident{Name: "err"},
Op: token.NEQ,
Y: &ast.Ident{Name: "nil"},
},
}
Ссылки:
- поиграться
- почитать
pkg.go.dev
ast package - go/ast - Go Packages
Package ast declares the types used to represent syntax trees for Go packages.
Слайды моего доклада “Advanced debugging techniques in different environments” на Kyiv Go Meetup July 2019:
- демо проект link
- слайды файлом link
- slideshare link
Вопросы пиши в личку: @a_soldatenko
- демо проект link
- слайды файлом link
- slideshare link
Вопросы пиши в личку: @a_soldatenko
Note #9 Когда лучше использовать именнованые параметры в функциях, определеных в интерфейсах?
Ели нам попадается такой код, то не совсем понятно что такое
Сразу же последует PR с чем-то вроде такого:
Так намного лучше :)
Но иногда есть более спорный кейс, в котором называть не объязательно:
🍺
Ели нам попадается такой код, то не совсем понятно что такое
str
или int
O_O:type runner interface {
run(context.Context, string, int)
}
Сразу же последует PR с чем-то вроде такого:
2c2
< run(context.Context, string, int)
---
> run(ctx context.Context, service string, instances int)
4d3
<
Так намного лучше :)
Но иногда есть более спорный кейс, в котором называть не объязательно:
type Enroller interface {
Enroll(*User, *Course) error
}
// P.S.
func main(){println("не забываем, что код пишется, еще и для наших коллеги, а не только для того, чтобы его можно было запустить на проде!")}
🍺
Note #10 Напоминание самому себе:
В Go можно делать вызов метода, напрямую используя тип:
[1] https://play.golang.org/p/5TbFC1DsZyy
[2] https://golang.org/ref/spec#Method_expressions
В Go можно делать вызов метода, напрямую используя тип:
package mainlinks:
import (
"fmt"
)
type Person struct {
Name string
}
func (p Person) Say() {
fmt.Println("Go for two me and", p.Name)
}
func main() {
p := Person{"%username%"}
// Все варианты эквивалентны
p.Say()
Person.Say(p)
(Person).Say(p)
f1 := Person.Say; f1(p)
f2 := (Person).Say; f2(p)
}
[1] https://play.golang.org/p/5TbFC1DsZyy
[2] https://golang.org/ref/spec#Method_expressions
go.dev
The Go Programming Language Specification - The Go Programming Language
Note #11: Go 2 и числовые литералы
Tl;dr в Go версии 2 собираются добавить некоторые изменения, которые затронут числовые литералы. Так это и так все знают: подумали Вы?
Давайте посмотрим, что же уже сейчас есть в go репо в главной ветке (master branch):
Один из самых заметных для меня это конечно _ в цифрах).
Небольшой примерчик:
Итак:
Oops 😬
Попытка номер 2:
Go 1.13RC1:
🎉🎉🎉🎉
P.S. Не совсем понятно почему это вроде как должно быть в Go2, а попало в Go 1.13 … наверное я что-то упустил, пойду читать GIthub…
[1] https://go.googlesource.com/proposal/+/master/design/19308-number-literals.md
Tl;dr в Go версии 2 собираются добавить некоторые изменения, которые затронут числовые литералы. Так это и так все знают: подумали Вы?
Давайте посмотрим, что же уже сейчас есть в go репо в главной ветке (master branch):
$ git clone [email protected]:golang/go.git
$ cd go/src && ./all.bash
$ go version devel +eee07a8e68 Wed Aug 21 15:20:00 2019 +0000 darwin/amd64
Один из самых заметных для меня это конечно _ в цифрах).
Небольшой примерчик:
package main
func main() {
println("1_200_000 -> ", 1_200_000)
println("3.1415_9265 -> ", 3.1415_9265)
println("0b0110_1101_1101_0010 -> ",0b0110_1101_1101_0010)
// println("0___ -> ", 0___) invalid example from discussion
// println(" 0__.0__e-0__ -> ",0__.0__e-0__) invalid example from discussion
// println("1__2", 1__2) invalid
}
Итак:
$ go version
$ go1.12.7 darwin/amd64
$ go run main.go
# command-line-arguments
./main.go:4:28: syntax error: unexpected _200_000, expecting comma or )
./main.go:5:35: syntax error: unexpected _9265, expecting comma or )
./main.go:6:39: syntax error: unexpected b0110_1101_1101_0010, expecting comma or )
Oops 😬
Попытка номер 2:
./go version
devel +eee07a8e68 Wed Aug 21 15:20:00 2019 +0000 darwin/amd64
./go run main.go
1_200_000 -> 1200000
3.1415_9265 -> +3.141593e+000
0b0110_1101_1101_0010 -> 28114
Go 1.13RC1:
go get golang.org/dl/go1.13rc1
go1.13rc1 run main.go
1_200_000 -> 1200000
3.1415_9265 -> +3.141593e+000
0b0110_1101_1101_0010 -> 28114
🎉🎉🎉🎉
P.S. Не совсем понятно почему это вроде как должно быть в Go2, а попало в Go 1.13 … наверное я что-то упустил, пойду читать GIthub…
[1] https://go.googlesource.com/proposal/+/master/design/19308-number-literals.md
Note #12: defer statements in infinite loops
Длинный стек отложенных вызовов может занимать много памяти, как Вы уже догадались такой код будет стремительно течь 💦:
Отловить данную проблему поможет статический анализатор:
deferlint:
либо staticcheck
Иногда данная ситуация абсолютно валидная, поэтому
Кстати,
Исправить данную ситуацию возможно, обернув
Потенциально, любой цикл, а особенно бесконечный, может служить причиной утечки памяти.
Links:
[1] Если вдруг вы пропустили статью о том, как написать свой линтер использую go/analysis, то вот https://arslan.io/2019/06/13/using-go-analysis-to-write-a-custom-linter/
Длинный стек отложенных вызовов может занимать много памяти, как Вы уже догадались такой код будет стремительно течь 💦:
$ cat main.go
package main
func g()
func f() {
for {
defer g()
}
}
func main() {
f()
}
Отловить данную проблему поможет статический анализатор:
deferlint:
go vet -vettool=$(which deferlint) .
# github.com/andriisoldatenko/golang_for_two
./main.go:10:4: defer in loop found "defer g()"
либо staticcheck
staticcheck
main.go:10:4: defers in this infinite loop will never run (SA5003)
Иногда данная ситуация абсолютно валидная, поэтому
staticcheck
пытается найти циклы без условий или брейков, чтобы отметить такой кейс, это помогает бороться с ложными срабатываниями.Кстати,
deferlint
- отличный пример, как написать свой линтер[1].Исправить данную ситуацию возможно, обернув
defer
в анонимную функцию, чтобы гарантированно ваша отложенная функция была вызвана вовремя.func f() {
for {
func(){
defer g()
}()
}
}
Потенциально, любой цикл, а особенно бесконечный, может служить причиной утечки памяти.
defer
следует гарантированно выполнять сразу же после того, как мы освободили ресурс, который нам уже больше не нужен. А иногда - это может происходить в цикле.Links:
[1] Если вдруг вы пропустили статью о том, как написать свой линтер использую go/analysis, то вот https://arslan.io/2019/06/13/using-go-analysis-to-write-a-custom-linter/
Note #13: go doc with colors
Если вы используете
Код очень простой и не странно, что принимает те же параметры что и
Link: https://github.com/inancgumus/godocc
Установить можно так:
Если вы используете
go doc
, для быстрого доступа к go документации, есть интересная идея как это все разукрасить:func main() {
args := []string{"doc"}
args = append(args, os.Args[1:]...)
cmd := exec.Command("go", args...)
cmd.Env = os.Environ()
output, _ := cmd.CombinedOutput()
stdout := colorable.NewColorableStdout()
err := quick.Highlight(stdout, string(output),
"go", "terminal256", style)
stdout.Write([]byte("\033[0m\n"))
}
Код очень простой и не странно, что принимает те же параметры что и
go doc
:trollface:, как описал автор :)Link: https://github.com/inancgumus/godocc
Установить можно так:
go get -u github.com/inancgumus/godocc
GODOCC_STYLE=monokai godocc time Unix
Note #14 argument reusing in fmt.Printf
Бывает необходимость напечатать несколько раз одно и тоже значение или значение и тип:
Это легко переписать, используя индексы аргументов:
more details: https://golang.org/pkg/fmt/
Бывает необходимость напечатать несколько раз одно и тоже значение или значение и тип:
fmt.Printf("Num: %d %d\n", 2, 2)
// or
fmt.Printf("Num: %d %T\n", 2, 2)
Это легко переписать, используя индексы аргументов:
fmt.Printf("Num: %d\n", 42)
fmt.Printf("Num: %d %[1]d %[1]d %[2]d %[2]d", 2, 3)
}
more details: https://golang.org/pkg/fmt/
Note #15 Go и зарезервированные ключевые слова
Ключевые слова в Go можно переопределять, НО никогда не стоит так делать!
Такой код, как Вы уже догадались, вполне себе валидный код в Go:
Как следствие:
И staticcheck или go vet ничего нам не сказали :(
И в конце, чтобы запутать своих коллег еще сильнее, возможно написать так:
P.S. SyntaxError: invalid syntax было бы лучше :)
Links:
[1] https://golang.org/ref/spec#Predeclared_identifiers
[2] https://play.golang.org/p/6OW0pJMvgQk
Ключевые слова в Go можно переопределять, НО никогда не стоит так делать!
Такой код, как Вы уже догадались, вполне себе валидный код в Go:
package mainИ мы получим в результате:😱:
import (
"fmt"
)
func main() {
const iota = iota
fmt.Println(iota, iota, iota)
}
0 0 0
.Как следствие:
const (0 0 0
a = iota
b
c
)
fmt.Println(a, b, c)
И staticcheck или go vet ничего нам не сказали :(
И в конце, чтобы запутать своих коллег еще сильнее, возможно написать так:
type int struct{}Компилятор подскажет ошибку:
func main() {
var i int
i++
fmt.Println(i)
}
invalid operation: i++ (non-numeric type int)
o_OP.S. SyntaxError: invalid syntax было бы лучше :)
Links:
[1] https://golang.org/ref/spec#Predeclared_identifiers
[2] https://play.golang.org/p/6OW0pJMvgQk
Note #16 GopherCon 2019 videos
Подвезли видео с GopherCon 2019 🎉🎉🎉
https://www.youtube.com/playlist?list=PL2ntRZ1ySWBdDyspRTNBIKES1Y-P__59_
Update: Лайтинг талкс: https://www.youtube.com/playlist?list=PL2ntRZ1ySWBedT1MDWF4xAD39vAad0DBT
P.S. пишите в личку ,если что-то по вашему мнению must have посмотреть, сделаем отдельный обзор! Enjoy!
Подвезли видео с GopherCon 2019 🎉🎉🎉
https://www.youtube.com/playlist?list=PL2ntRZ1ySWBdDyspRTNBIKES1Y-P__59_
Update: Лайтинг талкс: https://www.youtube.com/playlist?list=PL2ntRZ1ySWBedT1MDWF4xAD39vAad0DBT
P.S. пишите в личку ,если что-то по вашему мнению must have посмотреть, сделаем отдельный обзор! Enjoy!
YouTube
GopherCon 2019
Share your videos with friends, family, and the world
Note # 17 Скомпилируется или нет? Или игра с ссылками.
Есть пример программы, которая скорее всего не скомпилируется?! :)
Итак перед тем как копировать код и запускать на play.golang.org, я решил немного освежить как же работают ссылки в Go. Есть небольшой пример:
Думаю тут все и так понятно:
Проблема лишь в том, что пока, я не приблизились к нашему первоначальному примеру ни на шаг.
И тут я вспомнил, то факт, что ссылка, может ссылаться на любой тип, в том числе, и быть ссылкой на ссылку, т.е. можно написать
P.S. я думаю теперь вы догадались, какой правильный ответ.
Есть пример программы, которая скорее всего не скомпилируется?! :)
Program:
package main
import (
"fmt"
)
var g *int
func f(p *****int) { g = ****p }
func main() {
var i int
j := &i
k := &j
l := &k
m := &l
f(&m)
fmt.Printf("%T\n", &m)
fmt.Printf("%T", f)
}
Итак перед тем как копировать код и запускать на play.golang.org, я решил немного освежить как же работают ссылки в Go. Есть небольшой пример:
func main() {
var i = 42
var j = &i
fmt.Println("i = ", i)
fmt.Println("j = ", j)
fmt.Println("*j = ", *j)
}
Думаю тут все и так понятно:
// Output
i = 100
j = 0xc0000160b8
*j = 100
Проблема лишь в том, что пока, я не приблизились к нашему первоначальному примеру ни на шаг.
И тут я вспомнил, то факт, что ссылка, может ссылаться на любой тип, в том числе, и быть ссылкой на ссылку, т.е. можно написать
**p
(dereferencing a pointer to pointer).func main() {
var i = 42
var p = &i
var pp = &p
fmt.Println("pp = ", pp)
// Dereferencing a pointer to pointer
fmt.Println("*pp = ", *pp)
fmt.Println("**pp = ", **pp)
}
pp = 0xc0000bc010
*pp = 0xc0000c2000
**pp = 42
P.S. я думаю теперь вы догадались, какой правильный ответ.
Goto Program
Note #18 gotip 🔨
P.S. код
gotip
консольная утилита, которая помогает скомпилировать go
из мастера и очень быстро проверить, пофиксили ли баг в мастере или совместимость проекта с последней версией (origin/master).$ go get -v golang.org/dl/gotip
$ gotip download
………………………….
…. Long output…. Here…. ☕️☕️☕️
………………………….
$ gotip version
go version devel +307544f Wed Aug 28 15:49:59 2019 +0000 darwin/amd64
$ gotip run main.go
P.S. код
gotip
довольно простой -> https://github.com/golang/dl/blob/master/gotip/main.go#L37Note #19 Reduce sturct size (maligned) 📄
Недавно много говорили, о том что одна и та же структура (type struct), с разными типами полей и с разным порядком, может занимать разное кол-во памяти в зависимости от того, как расположить в памяти компьютера с учетом всех отступов. Более детально прочитать можно в вики [1], почему именно так происходит.
Хотелось бы, чтобы компилятор самостоятельно делал такие оптимизации.
Возьмем структура
Хорошо что есть отличный линтер[2], который напомнит нам, что можно что-то улучшить:
либо
Links:
- https://en.wikipedia.org/wiki/Data_structure_alignment
- https://github.com/mdempsky/maligned
Недавно много говорили, о том что одна и та же структура (type struct), с разными типами полей и с разным порядком, может занимать разное кол-во памяти в зависимости от того, как расположить в памяти компьютера с учетом всех отступов. Более детально прочитать можно в вики [1], почему именно так происходит.
Хотелось бы, чтобы компилятор самостоятельно делал такие оптимизации.
Возьмем структура
A
:$ cat main.go
// A is my struct
type A struct {
a bool // 1 byte
b float64 // 8 bytes
c int32 // 4 bytes
}
Хорошо что есть отличный линтер[2], который напомнит нам, что можно что-то улучшить:
$ golangci-lint run --enable=maligned main.go
main.go:4:8: struct of size 24 bytes could be of size 16 bytes (maligned)
type A struct {
^
либо
go get github.com/mdempsky/maligned
$ maligned .
/Users/andrii/work/golang_for_two/main.go:4:8: struct of size 24 could be 16
Links:
- https://en.wikipedia.org/wiki/Data_structure_alignment
- https://github.com/mdempsky/maligned
Note #20 import proverbs 🧠
Советы Роба Пайка всегда должны быть под рукой:
or
P.S. в исходниках есть пасхалочка 🥚
Links:
- https://go-proverbs.github.io/
- https://github.com/andriisoldatenko/proverbs/blob/master/pkg/proverbs.go
Советы Роба Пайка всегда должны быть под рукой:
go run github.com/andriisoldatenko/proverbs
Go Proverbs, by Rob Pike
Don't communicate by sharing memory, share memory by communicating.
Concurrency is not parallelism.
Channels orchestrate; mutexes serialize.
The bigger the interface, the weaker the abstraction.
Make the zero value useful.
interface{} says nothing.
Gofmt's style is no one's favorite, yet gofmt is everyone's favorite.
A little copying is better than a little dependency.
Syscall must always be guarded with build tags.
Cgo must always be guarded with build tags.
Cgo is not Go.
With the unsafe package there are no guarantees.
Clear is better than clever.
Reflection is never clear.
Errors are values.
Don't just check errors, handle them gracefully.
Design the architecture, name the components, document the details.
Documentation is for users.
Don't panic.
or
package main
import (
_ "github.com/andriisoldatenko/proverbs/pkg"
)
func main() {}
P.S. в исходниках есть пасхалочка 🥚
Links:
- https://go-proverbs.github.io/
- https://github.com/andriisoldatenko/proverbs/blob/master/pkg/proverbs.go
Note #21 Contributing to the os Package 💬
Недавно начал смотреть доклады c GopherCon 2019. Понравился доклад от молодого и перспективного разработчика из Лондона Оливера Стэнбома,
который полностью соответсвует моим критериям идеального доклада:
- реальная история из жизни о найденном баге;
- сложные будни и куча emailов на тему как же пофиксить этот баг на всех ОС;
- завести PR получить заветные +2 (перед этим подумать зачем я вообще брался за этот баг)
- вуаля баг пофикшен и попал в релиз go1.12 🎉🎉🎉
Сам баг довольно простой:
Оригинальный фикс в проекте у Оливера занимает 1 экран, но финальный фикс в Go для unix и solaris поместился в +774 -229 добавленных и удаленных строк кода соответсвенно!
P.S.
ссылка на доклад -> https://www.youtube.com/watch?v=cQgpNkKi9aA
🍺
Недавно начал смотреть доклады c GopherCon 2019. Понравился доклад от молодого и перспективного разработчика из Лондона Оливера Стэнбома,
который полностью соответсвует моим критериям идеального доклада:
- реальная история из жизни о найденном баге;
- сложные будни и куча emailов на тему как же пофиксить этот баг на всех ОС;
- завести PR получить заветные +2 (перед этим подумать зачем я вообще брался за этот баг)
- вуаля баг пофикшен и попал в релиз go1.12 🎉🎉🎉
Сам баг довольно простой:
func main() {
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
panic(err)
}
err = createVeryLongFilePath(tmpDir)
if err != nil {
panic(err)
}
err = os.RemoveAll(tmpDir)
if err != nil {
panic(err)
}
}
os: RemoveAll fails for long file paths
Оригинальный фикс в проекте у Оливера занимает 1 экран, но финальный фикс в Go для unix и solaris поместился в +774 -229 добавленных и удаленных строк кода соответсвенно!
P.S.
ссылка на доклад -> https://www.youtube.com/watch?v=cQgpNkKi9aA
🍺