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
🍺
Note #22 Vulnerability Static Analysis for Containers 🛡🐳
Quay.io содержит интересный репорт:
Все это осуществляется с помощью тула
Недавно мне пришлось фиксить такие High severity issues… 🤔
Чтобы запустить
1) Свежий дамп с базой данных CVE: тут 2 варианта либо самостоятельно залить дамп в пустую PostgreSQL БД, либо взять готовый имедж PostgreSQL с уже предустановленным дампом, либо накатить последний дамп руками занимает минут 40 :( Но добрый человек все уже сделал за Вас):
2) Запустить clair api локально
3) и установить
Дальше можно фиксить уязвимости, как правило, просто обновив некоторые библиотеки и вуаля 🎉, возвращаем долг опенсорсу, в виде PRs например в grafana ;)
P.S. Также данные проверки можно добавить к своему CI/CD.
https://ibb.co/XLdPmQQ
Quay.io содержит интересный репорт:
Quay Security Scanner has detected 74 vulnerabilities.
Patches are available for 2 vulnerabilities.
4 High-level vulnerabilities.
Все это осуществляется с помощью тула
clair
от CoreOS team - который умеет сканировать ваши докер имеджи на разные CVE уязвимости.Недавно мне пришлось фиксить такие High severity issues… 🤔
Чтобы запустить
clair
локально нам понадобится:1) Свежий дамп с базой данных CVE: тут 2 варианта либо самостоятельно залить дамп в пустую PostgreSQL БД, либо взять готовый имедж PostgreSQL с уже предустановленным дампом, либо накатить последний дамп руками занимает минут 40 :( Но добрый человек все уже сделал за Вас):
docker run -p 5432:5432 -d --name db arminc/clair-db:latest
2) Запустить clair api локально
docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:latest
3) и установить
clair-scanner
локально (прочитать тут https://github.com/arminc/clair-scanner)clair-scanner -r grafana_report.txt --ip=192.168.1.200 grafana/grafana:master
2019/09/02 17:25:16 [INFO] ▶️ Start clair-scanner
2019/09/02 17:25:20 [INFO] ▶️ Server listening on port 9279
2019/09/02 17:25:20 [INFO] ▶️ Analyzing a61298a1d179786c2c176dc6c3e20c2d0cad25582e53a7bbec428fc4370a679e
...
73a18bb7d185e7c6763c97311263a8b773ce0641adb2186f7291702f4ef437bd
2019/09/02 17:25:24 [INFO] ▶️ Image [grafana/grafana:master] contains NO unapproved vulnerabilities
Дальше можно фиксить уязвимости, как правило, просто обновив некоторые библиотеки и вуаля 🎉, возвращаем долг опенсорсу, в виде PRs например в grafana ;)
P.S. Также данные проверки можно добавить к своему CI/CD.
https://ibb.co/XLdPmQQ
Note #23 Top 10 talks from GopherCon 2019 based on youtube stats 🚀
После некоторого кол-ва времение и неудачных просмотренных докладов решил взглянуть на playlist c последнего GopherCon 👀 статистики:
"121|4562|GopherCon 2019: Russ Cox - On the Path to Go 2"
"136|3648|GopherCon 2019: Elias Naur - Portable, Immediate Mode GUI Programs for Mobile and Desktop in 100% Go"
"83|3204|GopherCon 2019: Ian Lance Taylor -Generics in Go"
"114|3161|GopherCon 2019: Mat Ryer - How I Write HTTP Web Services after Eight Years"
"110|2704|GopherCon 2019: Marwan Sulaiman - Handling Go Errors"
"89|2534|GopherCon 2019: Dave Cheney - Two Go Programs, Three Different Profiling Techniques"
"33|2250|GopherCon 2019: Michael McLoughlin - Better x86 Assembly Generation from Go"
"91|1687|GopherCon 2019: Chris Hines - Death by 3,000 Timers: Streaming Video-on-Demand for Cable TV"
"35|1534|GopherCon 2019: Katie Hockman - Go Module Proxy: Life of a Query"
"46|1509|GopherCon 2019: Rebecca Stambler - Go, pls stop breaking my editor"
P.S. пошел смотреть дальше
P.P.S сырые данные https://gist.github.com/andriisoldatenko/ec7e551ec5c8d0d10d446e87909cc723 взял с помощью пару запросов curl && jq
P.P.P.S посчитал вот так:
После некоторого кол-ва времение и неудачных просмотренных докладов решил взглянуть на playlist c последнего GopherCon 👀 статистики:
"121|4562|GopherCon 2019: Russ Cox - On the Path to Go 2"
"136|3648|GopherCon 2019: Elias Naur - Portable, Immediate Mode GUI Programs for Mobile and Desktop in 100% Go"
"83|3204|GopherCon 2019: Ian Lance Taylor -Generics in Go"
"114|3161|GopherCon 2019: Mat Ryer - How I Write HTTP Web Services after Eight Years"
"110|2704|GopherCon 2019: Marwan Sulaiman - Handling Go Errors"
"89|2534|GopherCon 2019: Dave Cheney - Two Go Programs, Three Different Profiling Techniques"
"33|2250|GopherCon 2019: Michael McLoughlin - Better x86 Assembly Generation from Go"
"91|1687|GopherCon 2019: Chris Hines - Death by 3,000 Timers: Streaming Video-on-Demand for Cable TV"
"35|1534|GopherCon 2019: Katie Hockman - Go Module Proxy: Life of a Query"
"46|1509|GopherCon 2019: Rebecca Stambler - Go, pls stop breaking my editor"
P.S. пошел смотреть дальше
P.P.S сырые данные https://gist.github.com/andriisoldatenko/ec7e551ec5c8d0d10d446e87909cc723 взял с помощью пару запросов curl && jq
P.P.P.S посчитал вот так:
jq '.items[] | .statistics.likeCount + "|" + .statistics.viewCount + "|" +.snippet.title' statistics.json |sort -t│
\| -r -k 1,1nr -k 2,2nr | head
Gist
gophercon19_raw.json
GitHub Gist: instantly share code, notes, and snippets.
🇺🇦 Go for two :)
Note #23 Top 10 talks from GopherCon 2019 based on youtube stats 🚀 После некоторого кол-ва времение и неудачных просмотренных докладов решил взглянуть на playlist c последнего GopherCon 👀 статистики: "121|4562|GopherCon 2019: Russ Cox - On the Path to Go…
для читабельности:
1. GopherCon 2019: Russ Cox - On the Path to Go 2
2. GopherCon 2019: Elias Naur - Portable, Immediate Mode GUI Programs for Mobile and Desktop in 100% Go
3. GopherCon 2019: Ian Lance Taylor -Generics in Go
4. GopherCon 2019: Mat Ryer - How I Write HTTP Web Services after Eight Years
5. GopherCon 2019: Marwan Sulaiman - Handling Go Errors
6. GopherCon 2019: Dave Cheney - Two Go Programs, Three Different Profiling Techniques
7. GopherCon 2019: Michael McLoughlin - Better x86 Assembly Generation from Go
8. GopherCon 2019: Chris Hines - Death by 3,000 Timers: Streaming Video-on-Demand for Cable TV
9. GopherCon 2019: Katie Hockman - Go Module Proxy: Life of a Query
10. GopherCon 2019: Rebecca Stambler - Go, pls stop breaking my editor
1. GopherCon 2019: Russ Cox - On the Path to Go 2
2. GopherCon 2019: Elias Naur - Portable, Immediate Mode GUI Programs for Mobile and Desktop in 100% Go
3. GopherCon 2019: Ian Lance Taylor -Generics in Go
4. GopherCon 2019: Mat Ryer - How I Write HTTP Web Services after Eight Years
5. GopherCon 2019: Marwan Sulaiman - Handling Go Errors
6. GopherCon 2019: Dave Cheney - Two Go Programs, Three Different Profiling Techniques
7. GopherCon 2019: Michael McLoughlin - Better x86 Assembly Generation from Go
8. GopherCon 2019: Chris Hines - Death by 3,000 Timers: Streaming Video-on-Demand for Cable TV
9. GopherCon 2019: Katie Hockman - Go Module Proxy: Life of a Query
10. GopherCon 2019: Rebecca Stambler - Go, pls stop breaking my editor
Note #24 Go и runtime
Существует много споров на тему
C одной стороны в Go есть рантайм, который написан на Go в отличии от Java(написан на С). C точки зрения архитектуры, рантайм - это просто коллекция нескольких уникальных частей, самые важные из которых: сборщик мусора и планировщик горутин (goroutine scheduler).
С другой стороны, Go рантайм также реализует фичи, которые экспортируются наружу c помощью пакета
Либо вывести сколько памяти занимает ваша программа:
Note: Также важно понимать, что Go рантайм не включает в себя виртуальную машину, а код программы на Go компилируется сразу в машинный код, кстати это позволяет нам так легко писать программы, которые легко портируются на разные ОС. Поэтому в контексте Go - когда говорят Go и runtime - это обычно имя пакета, а не виртуальное окружение в котором программа на Go запускается.
Существует много споров на тему
Go рантайм
и Go
пакета runtime
. Давайте разберемся с этим вопросом.C одной стороны в Go есть рантайм, который написан на Go в отличии от Java(написан на С). C точки зрения архитектуры, рантайм - это просто коллекция нескольких уникальных частей, самые важные из которых: сборщик мусора и планировщик горутин (goroutine scheduler).
С другой стороны, Go рантайм также реализует фичи, которые экспортируются наружу c помощью пакета
runtime
. C помощью пакета runtime
можно осуществлять управление сборщиком мусора и выводить различную дебаг информация см (runtime/debug).Либо вывести сколько памяти занимает ваша программа:
package main
import (
"runtime"
"fmt"
"time"
)
func PrintMememoryStats() {
var m runtime.MemStats
// The returned memory allocator statistics are up to date as of the call to ReadMemStats. This is in contrast with a heap profile, which is a snapshot as of the most recently completed garbage collection cycle.
runtime.ReadMemStats(&m)
fmt.Printf("Alloc = %v Mb", m.Alloc / 1024 / 1024)
fmt.Printf(" TotalAlloc = %v Mb", m.TotalAlloc / 1024 / 1024)
fmt.Printf(" Sys = %v Mb", m.Sys / 1024 / 1024)
fmt.Printf(" NumGC = %v\n", m.NumGC)
}
func main() {
PrintMememoryStats()
var total [][]int
for i := 0; i<3; i++ {
array := make([]int, 0, 4200000)
total = append(total, array)
PrintMememoryStats()
time.Sleep(time.Second)
}
PrintMememoryStats()
runtime.GC()
PrintMememoryStats()
}
Note: Также важно понимать, что Go рантайм не включает в себя виртуальную машину, а код программы на Go компилируется сразу в машинный код, кстати это позволяет нам так легко писать программы, которые легко портируются на разные ОС. Поэтому в контексте Go - когда говорят Go и runtime - это обычно имя пакета, а не виртуальное окружение в котором программа на Go запускается.
Note #25 Github Actions и Go
Решил посмотреть как обстоят дела у Github Actions и Go:
>Thanks for signing up for GitHub Actions!
>This account is already on the waitlist for the GitHub Actions Beta!
А пока я жду 🤣 Daniel Martí уже сделал отличный обзор[1] того, что уже работает 👍 и что не работает 👎 [2]
Полный пример конфигураций Github Actions и goreleaser и go1.13 можно найти в github репке проекта
Links:
[1] https://github.com/mvdan/github-actions-golang
[2] https://github.com/actions/setup-go/issues
[3] https://github.com/toshimaru/nyan/blob/master/.github/workflows/go.yml
P.S. кто знает как раздобыть инвайт напишите в личку @a_soldatenko
Решил посмотреть как обстоят дела у Github Actions и Go:
>Thanks for signing up for GitHub Actions!
>This account is already on the waitlist for the GitHub Actions Beta!
А пока я жду 🤣 Daniel Martí уже сделал отличный обзор[1] того, что уже работает 👍 и что не работает 👎 [2]
Полный пример конфигураций Github Actions и goreleaser и go1.13 можно найти в github репке проекта
nyan
aka colored cat [3]:Links:
[1] https://github.com/mvdan/github-actions-golang
[2] https://github.com/actions/setup-go/issues
[3] https://github.com/toshimaru/nyan/blob/master/.github/workflows/go.yml
P.S. кто знает как раздобыть инвайт напишите в личку @a_soldatenko
Note #26 LEAP year
Часто на собеседованиях в качестве разминки просят написать функцию, которая определяет является ли год высокосным или нет. Также подобную задачу можно найти в онлайн соревнованиях как SPOJ или CodeChef.
Т.е. сигнатура функции выглядит примерно так:
Самое близкое что я нашел было https://golang.org/pkg/time/#Time.YearDay:
> returns the day of the year specified by t, in the range [1,365] for non-leap years, and [1,366] in leap years.
После прочитанного пришла тривиальная идея, создать дату использую номер года и некоторые дефолтные параметры а именно последний день года, что позволит нам использовать метод
P.S. в качестве упражнения можно реализовать
P.P.S Отличный пример можно найти в доках
Links:
SPOJ - https://www.spoj.com/problems/ORTL1P07/
CodeChef - https://www.codechef.com/problems/LEAPY
алгоритм - https://en.wikipedia.org/wiki/Leap_year#Algorithm
Часто на собеседованиях в качестве разминки просят написать функцию, которая определяет является ли год высокосным или нет. Также подобную задачу можно найти в онлайн соревнованиях как SPOJ или CodeChef.
Т.е. сигнатура функции выглядит примерно так:
func IsLeapYear(y int) boolТак как использование стандартной библиотеки языка обычно не запрещено, то вдруг в голову пришла идея поискать, что там есть, после неудачного поиска по докам пакета
time
, как и ожидалось ничего подходящего не нашлось, я решил чуток подумать и сделать себе :coffee:Самое близкое что я нашел было https://golang.org/pkg/time/#Time.YearDay:
> returns the day of the year specified by t, in the range [1,365] for non-leap years, and [1,366] in leap years.
После прочитанного пришла тривиальная идея, создать дату использую номер года и некоторые дефолтные параметры а именно последний день года, что позволит нам использовать метод
YearDay
, чтобы проверить 31 декабря какой день 365-ый или 366-ой?func IsLeapYear(y int) bool {Далее естественно я полез смотреть исходники
year := time.Date(y, time.December, 31, 0, 0, 0, 0, time.Local)
days := year.YearDay()
if days > 365 {
return true
} else {
return false
}
}
time.YearDay
, и наткнулся на src/time/time.go:1329
func isLeap(year int) bool {Т.е полезная, но не экспортируемая функция isLeap :)
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
P.S. в качестве упражнения можно реализовать
func isLeap(year big.Int) bool
. P.P.S Отличный пример можно найти в доках
math/big
как вычислить фибоначчи используя арифметику больших чисел.Links:
SPOJ - https://www.spoj.com/problems/ORTL1P07/
CodeChef - https://www.codechef.com/problems/LEAPY
алгоритм - https://en.wikipedia.org/wiki/Leap_year#Algorithm
Note #27 Evolution of reverse string "Hello, 世界"
4 года назад мне попался интересный вопрос: как же развернуть строку используя Го?! Сложность заключается в том, чтобы не сломать UTF-8 символы которые могут быть в строке. Т.е. если решать в лоб то получим:
В 2009 Russ Cox в девелоперской рассылке golang-nuts [3] предложил решить эту задачку так:
Немного громоздко, но все же работает и сейчас (оставил оригинальное решение, понятное дело, что можно улучшить, Russ писал думаю пару минут):
>> fmt.Println(reverseString("世Hello, 世"))
>> 世 ,olleH世
Если не много упростить, используя тот факт, что строку можно конвертировать на прямую в
Идея та же, но код получился чуть более лаконичный.
Самое быстрое решение и не самое лаконичное:
И самый интересный на мой взгляд вариант с помощью
Это не самое быстрое решение, но оно показывает как используя замыкание мы сохраняем промежуточное значение в переменной
P.S. В качестве упражнения я рекомендую реализовать
"as⃝df̅" превратить в "f̅ds⃝a"
Links:
[1] https://github.com/golang/example/blob/master/stringutil/reverse.go
[2] https://golang.org/pkg/unicode/utf8/#DecodeRuneInString
[3] https://groups.google.com/forum/#!topic/golang-nuts/oPuBaYJ17t4
[4] http://rosettacode.org/wiki/Reverse_a_string
4 года назад мне попался интересный вопрос: как же развернуть строку используя Го?! Сложность заключается в том, чтобы не сломать UTF-8 символы которые могут быть в строке. Т.е. если решать в лоб то получим:
��� ,olleH���
, а хотелось бы 界世 ,olleH
.В 2009 Russ Cox в девелоперской рассылке golang-nuts [3] предложил решить эту задачку так:
func reverseString(s string) string {
n := 0
rune := make([]rune, len(s))
for _, r := range s {
rune[n] = r
n++
}
rune = rune[0:n]
// Reverse
for i := 0; i < n/2; i++ {
rune[i], rune[n-1-i] = rune[n-1-i], rune[i]
}
// Convert back to UTF-8.
return string(rune)
}
Немного громоздко, но все же работает и сейчас (оставил оригинальное решение, понятное дело, что можно улучшить, Russ писал думаю пару минут):
>> fmt.Println(reverseString("世Hello, 世"))
>> 世 ,olleH世
Если не много упростить, используя тот факт, что строку можно конвертировать на прямую в
[]rune
без дополнительного цикла [1]:func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
Идея та же, но код получился чуть более лаконичный.
Самое быстрое решение и не самое лаконичное:
func ReverseFast(s string) string {
size := len(s)
buf := make([]byte, size)
for start := 0; start < size; {
r, n := utf8.DecodeRuneInString(s[start:])
start += n
utf8.EncodeRune(buf[size-start:], r)
}
return string(buf)
}
И самый интересный на мой взгляд вариант с помощью
defer
, рекомендую остановиться и подумать что же тут происходит на самом деле :func ReverseClosure(s string) (result string) {
for _, v := range s {
defer func(r rune) { result += string(r) }(v)
}
return
}
Это не самое быстрое решение, но оно показывает как используя замыкание мы сохраняем промежуточное значение в переменной
result
, для дальнейшего использования каждого defer вызова функции :)P.S. В качестве упражнения я рекомендую реализовать
func reverse(s string)
для так называемых “combining characters”. Те чтобы покрыть такой кейс:"as⃝df̅" превратить в "f̅ds⃝a"
Links:
[1] https://github.com/golang/example/blob/master/stringutil/reverse.go
[2] https://golang.org/pkg/unicode/utf8/#DecodeRuneInString
[3] https://groups.google.com/forum/#!topic/golang-nuts/oPuBaYJ17t4
[4] http://rosettacode.org/wiki/Reverse_a_string
Note # 28 fallthrough или “проваливаемся” дальше ⤵️
Go содержит интересное ключевое слово
Итак поехали 🚴♂️:
Т.е по дефолту в Go switch/case не проваливается дальше - это нужно делать явно используя ключевое слово
Не разрешается использовать в последнем операторе неважно это
Соответственно такой вариант вполне валидный:
Важный момент, "fallthrough" не разрешается использовать в связке с type switch:
Так же нельзя делать вложенные конструкции которые содержат
Useful links:
- ref - https://golang.org/ref/spec#Switch_statements
- wiki https://github.com/golang/go/wiki/Switch
Go содержит интересное ключевое слово
fallthrough
, которое на практике встречается довольно редко, его главная задача передать управление следующему оператору case
в условных конструкциях switch/case
. Итак поехали 🚴♂️:
func main() {
switch 42 {
case 42:
fmt.Println("First case: 42!")
fallthrough
default:
fmt.Println("Second case")
}
}
// First case: 42!
// Second case
Т.е по дефолту в Go switch/case не проваливается дальше - это нужно делать явно используя ключевое слово
fallthrough
.Не разрешается использовать в последнем операторе неважно это
case
или default
:func main() {
switch 42 {
case 42:
fmt.Println("First case: 42!")
default:
fmt.Println("Second case")
fallthrough
}
}
// cannot fallthrough final case in switch
Соответственно такой вариант вполне валидный:
func main() {
switch 42 {
default:
fmt.Println("Second case")
fallthrough
case 42:
fmt.Println("First case: 42!")
}
}
// First case: 42!
Важный момент, "fallthrough" не разрешается использовать в связке с type switch:
func main() {
var pi interface{} = 3.14
switch i := pi.(type) {
case int:
fmt.Printf("%v", i)
fallthrough
default:
fmt.Println("don't know the type")
}
}
// ./prog.go:18:3: cannot fallthrough in type switch
Так же нельзя делать вложенные конструкции которые содержат
fallthrough
☔️:func main() {
switch 42 {
case 42:
fmt.Println("First case: 42!")
if true {
fallthrough
}
case 1:
fmt.Println("First case: 1!")
}
}
// ./prog.go:18:4: fallthrough statement out of place
Useful links:
- ref - https://golang.org/ref/spec#Switch_statements
- wiki https://github.com/golang/go/wiki/Switch
Note #29 Testing.short или разделяем тестовые прогоны 📝
Недавно наткнулся на интересную тему: разделение Go тестов на быстрые или медленные те например unit и integration tests. Все собрал в короткую заметку:
A) Стандартный подход использую `testing.Short` [2]:
Если выполнить:
То мы пропустим тест
B) Использовать build tags самый, на мой взгляд, гибкий подход:
Те создаем
Далее просто запускаем:
С) Использовать -test.run RegExp [2]:
Можно именовать тесты с префиксом понятным всей команде:
И далее просто:
P.S. еще как вариант можно добавить разделение с помощью переменных окружения
А как сделано в вашем проекте? Поделиться можно в личку или чат
Links:
[1] https://golang.org/pkg/go/build/
[2] https://golang.org/cmd/go/#hdr-Testing_flags
[3] https://golang.org/pkg/testing/
Недавно наткнулся на интересную тему: разделение Go тестов на быстрые или медленные те например unit и integration tests. Все собрал в короткую заметку:
A) Стандартный подход использую `testing.Short` [2]:
func TestQuick(t *testing.T) {
...
}
func TestTimeConsuming(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
}
Если выполнить:
$ go test -short
То мы пропустим тест
TestTimeConsuming
и выполним только TestQuick
B) Использовать build tags самый, на мой взгляд, гибкий подход:
Те создаем
integration_test.go
файл и добавляем билд тэги [1]:// +build integration
func TestTimeConsuming(t *testing.T) {
// ...
}
Далее просто запускаем:
$ go test -tags=integration
С) Использовать -test.run RegExp [2]:
Можно именовать тесты с префиксом понятным всей команде:
func TestQuickUnit(t *testing.T) {
...
}
func TestIntegraion(t *testing.T) {
...
}
И далее просто:
$ go test -run Integration
$ go test -run Unit
P.S. еще как вариант можно добавить разделение с помощью переменных окружения
А как сделано в вашем проекте? Поделиться можно в личку или чат
Links:
[1] https://golang.org/pkg/go/build/
[2] https://golang.org/cmd/go/#hdr-Testing_flags
[3] https://golang.org/pkg/testing/