Что выведет код?
#код
func main() {
s := make([]int, 0, 5)
s = append(s, 1, 2, 3)
f := func(sl []int) {
sl = append(sl, 4)
sl[0] = 10
}
f(s)
s = append(s, 5)
fmt.Println(s)
}#код
Создается слайс len=0 и cap=5, далее в него записываем 1, 2, 3. Массив родитель не аллоцировался, так как до cap мы еще не дошли.
sl - копия s
Мы добавили в sl 4 и поменяли первый элемент(помним в голове, что sl ссылается на тот же массив родитель), и получается, что у sl len=4, cap=5. Массив родитель в памяти выглядит так: [10 2 3 4]
Довольные выходим из функции, и приходим к s, у которого len=3, cap=5 (мы же с ним ничего не делали). И получается, что массив родитель [10 2 3 4], но len у него 3, то есть по сути сам s выглядит как [10 2 3]. И как раз-таки при append мы добавляем 5 в ячейку где уже была 4, и перезаписываем ее
Please open Telegram to view this post
VIEW IN TELEGRAM
1 3🔥2❤1👍1
Хотели бы вы принять участие в бесплатном практическом созвоне, где мы напишем с нуля базовый микросервис на Go?
Anonymous Poll
66%
Да, интересно! Хочу посмотреть на реальный процесс разработки
29%
Возможно, зависит от темы и времени
6%
Нет, не интересно
Благодаря этому написание моков и подмена слоев на любую другую реализацию (например, юзали библиотеку БД gorm, а в v2-версии слоя решили перейти на самописные SQL запросы) превращается из боли и страданий, в кайф и красоту. На моем опыте я раз 20 переписывал слои сервиса, чтобы их просто замокать и сделать тесты, потому что все завязывались на реализации сущностей
type Speaker interface {
Speak() string
}
type Duck struct {
Name string
}
func (d Duck) Speak() string {
return fmt.Sprintf("%s говорит Кря", d.Name)
}
type Pigeon struct {
Name string
}
func (c Pigeon) Speak() string {
return fmt.Sprintf("%s говорит Гули-Гули", c.Name)
}
func main() {
animals := []Speaker{
Duck{Name: "Утка"},
Pigeon{Name: "Голубь"},
}
for _, a := range animals {
a.Speak()
}
}Please open Telegram to view this post
VIEW IN TELEGRAM
👏2 2❤1
Что выведет код?
#код
func main() {
mainSl := []string{"Test", "slices", "copying"}
var sl []string
copy(sl, mainSl)
sl1 := make([]string, 1, 3)
copy(sl1, mainSl)
fmt.Println(sl, sl1)
}#код
Код выведет:
Anonymous Poll
44%
[] [Test]
22%
[Test, slices, copying] [Test, slices, copying]
4%
[] [Test, slices, copying]
26%
Паника, копирование в nil-слайс
4%
[] []
😁2 2👏1 1
Лучшее объяснение этого вывода состоит в идее copy. Предназначена эта функция для копирования элементов слайса-родителя в слайс-ребенок, отвязывая от ссылки на массив родитель
То есть, если есть выделенная под элемент ячейка слайса, то copy сделает свою работу, а вот если ячейки не оказалось, то copy просто пожимает плечами.
Теперь важный момент на понимание слайса: выделенные ячейки - это не cap! Это len! Ровно по этому числу мы понимаем сколько проинициализированных ячеек в слайсе
В sl мы ничего не получили по причине того, что инициализация вида
var sl []string
это инициализация nil-слайса, у которого нет ни длины, ни капасити
💡Во втором примере у sl1 уже установлена длина 1 и капасити 3, следовательно copy переносит в инициализированную ячейку элемент
На просторах коммерческой разработки мало встречал использования этой функции, хотя и не понимаю почему
func main() {
sl := []int{1, 2, 3, 4}
part := sl[:2]
partByCopy := make([]int, 2)
copy(partByCopy, sl)
// Изменим sl, чтобы показать наследование ссылки на массив-родитель
sl[0] = 5
fmt.Println(part, partByCopy)
// Получаем вывод:[5 2] [1 2] -> получение базового ломтика, приводит к риску мутаций, в отличие от copy
}Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍2 2
Давайте согласуем удобное время для мита по написанию микросервиса
Anonymous Poll
19%
Сегодня
15%
25 июня
19%
26 июня
11%
27 июня
67%
Выходные
Что произойдет при запуске программы?
#код
var m = map[string]int{"a": 1}
func main() {
go Read()
time.Sleep(1 * time.Second)
go Write()
time.Sleep(1 * time.Minute)
}
func Read() {
for {
fmt.Println(m["a"])
}
}
func Write() {
for i := 0; ; i++ {
m[fmt.Sprintf("%d", i)] = i
}
}#код
Голосуем за время воскресного мита
Anonymous Poll
11%
11:00
17%
12:00
44%
17:00
28%
21:00
17%
Не могу в вс🙁
Go Level Up
Что произойдет при запуске программы? var m = map[string]int{"a": 1} func main() { go Read() time.Sleep(1 * time.Second) go Write() time.Sleep(1 * time.Minute) } func Read() { for { fmt.Println(m["a"]) } } func Write() { for i := 0;…
📌При запуске программы произойдет - бесконечный вывод 1 и фатальная ошибка fatal error: concurrent map read and map write
➡️Важно! Данный результат произойдет при версии го, где мапа реализована в виде бакетов, то есть до swiss table. Какой результат будет в новой версии, требует отдельного поста.➡️
💻Итак, вернемся к нашей старой доброй мапе на бакетах. Каждый раз, когда показываю менти этот код, они вчитываются в код и пытаются найти здесь скрытый смысл. Но нет, по сути все, что достаточно увидеть - чтение и запись в мапу из горутин 🔜🔜🔜 ошибка. Дело в том, что мапа не потокобезопасна. 🥳
➡️На моках постоянно отвечают так😳Но не понимают почему так и что это значит. Это значит, что как раз-таки из мапы нельзя читать и писать одновременно в связи с вероятностью обратиться к несуществующему эвакуированному куску памяти или вовсе вызвать гонку данных.
💬Причина: при эвакуации старые бакеты постепенно освобождаются и ключи-значения переходят в новые выделенные бакеты бОльшего количества. Так вот когда мы пишем мы сталкиваемся с риском эвакуации, а когда читаем с риском обратиться к несуществующему удаленному блоку памяти или непредсказуемым данным(из-за data race)🖥
➡️Важно! Данный результат произойдет при версии го, где мапа реализована в виде бакетов, то есть до swiss table. Какой результат будет в новой версии, требует отдельного поста.➡️
💻Итак, вернемся к нашей старой доброй мапе на бакетах. Каждый раз, когда показываю менти этот код, они вчитываются в код и пытаются найти здесь скрытый смысл. Но нет, по сути все, что достаточно увидеть - чтение и запись в мапу из горутин 🔜🔜🔜 ошибка. Дело в том, что мапа не потокобезопасна. 🥳
➡️На моках постоянно отвечают так😳Но не понимают почему так и что это значит. Это значит, что как раз-таки из мапы нельзя читать и писать одновременно в связи с вероятностью обратиться к несуществующему эвакуированному куску памяти или вовсе вызвать гонку данных.
💬Причина: при эвакуации старые бакеты постепенно освобождаются и ключи-значения переходят в новые выделенные бакеты бОльшего количества. Так вот когда мы пишем мы сталкиваемся с риском эвакуации, а когда читаем с риском обратиться к несуществующему удаленному блоку памяти или непредсказуемым данным(из-за data race)🖥
👍3❤2 1
type SafeMap struct {
sync.RWMutex
data map[string]int
}
func main() {
protectedMap := SafeMap{
data: map[string]int{"a": 1},
}
go protectedMap.Read()
time.Sleep(1 * time.Second)
go protectedMap.Write()
time.Sleep(1 * time.Minute)
}
func (sm *SafeMap) Read() {
for {
sm.RLock()
fmt.Println(sm.data["a"])
sm.RUnlock()
}
}
func (sm *SafeMap) Write() {
for i := 0; ; i++ {
sm.Lock()
sm.data[fmt.Sprintf("%d", i)] = i
sm.Unlock()
}
}Please open Telegram to view this post
VIEW IN TELEGRAM
Коллеги, спасибо за участие в опросе! Большинство выбрало вариант 17:00. 💻
🖱 Сегодня в 17:00 (МСК) созвон — обсудим как писать микросервис на го. Жду всех!📌
Please open Telegram to view this post
VIEW IN TELEGRAM
Коллеги, созвон по написанию микросервиса начинается. Всех жду
https://us04web.zoom.us/j/79268156565?pwd=dSYcbdVxZC0K0IJx97ubNHgoYIGt8w.1
https://us04web.zoom.us/j/79268156565?pwd=dSYcbdVxZC0K0IJx97ubNHgoYIGt8w.1
Zoom
Join our Cloud HD Video Meeting
Zoom is the leader in modern enterprise cloud communications.
❤4
Коллеги извиняюсь, зум у меня странно работает, крашится. Переходим в гугл мит https://meet.google.com/bfc-mioz-qhz
Google
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет код?
func main() {
runtime.GOMAXPROCS(1)
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
fmt.Println(n)
}(i)
}
wg.Wait()
}