Designing Go code with interface chaining vs requiring deps.
https://gist.github.com/joncalhoun/0cd99c9082d2ba210c5169082038a420
Note: этот gist от создателя https://gophercises.com/, он написал в твиттере: времени нет писать 2 статьи - ловите код :)
https://gist.github.com/joncalhoun/0cd99c9082d2ba210c5169082038a420
Note: этот gist от создателя https://gophercises.com/, он написал в твиттере: времени нет писать 2 статьи - ловите код :)
Gist
chain_vs_not.go
GitHub Gist: instantly share code, notes, and snippets.
В одном из недавних постов я писал, что люди требуют крови!: 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