Что выведет первая строка?
Anonymous Quiz
53%
[1 2 3 4 5]
11%
[1 99 3 4 5]
31%
[1 99 3 4 10]
6%
[1 2 3 4 10]
В какой момент Go устанавливает случайный seed для map?
Anonymous Quiz
42%
При создании новой map
28%
Один раз при старте программы
18%
Перед каждой итерацией range
12%
При каждом доступе к элементу map
❓ Что произойдет, если написать //go:generate перед функцией в коде?
Anonymous Quiz
5%
Код не скомпилируется
53%
Go выполнит указанную команду при генерации кода
13%
Go проигнорирует этот комментарий
10%
Это специальный комментарий для работы с интерфейсами
18%
Узнать ответ
❓ Что произойдёт, если вызвать runtime.Gosched() внутри функции без горутин
Anonymous Quiz
9%
Программа завершится с ошибкой.
53%
Ничего не произойдёт — код продолжит выполняться.
20%
Код приостановится на неопределённое время.
19%
Узнать ответ
❓Как передать неограниченное количество аргументов разных типов
Anonymous Quiz
12%
func myFunc(args ...int)
11%
func myFunc(args []interface{})
75%
func myFunc(args ...interface{})
3%
Узнать ответ
❓ Вам нужно выгрузить несколько строк из базы данных, какой метод будете исполльзовать?
Anonymous Quiz
51%
Query()
30%
QueryRow()
10%
Exec()
1%
Prepare()
0%
ProgLib()
6%
Узнать ответ
❓ Можно ли изменить символ в строке по индексу в Go?
Anonymous Quiz
12%
Да, можно, строки в Go изменяемы, как и массивы.
8%
Да, но только если строка содержит ASCII-символы, а не Unicode
5%
Можно, но только если строка объявлена с помощью var вместо const
70%
Нет, строки в Go неизменяемы, попытка изменить символ вызовет ошибку компиляции.
5%
Узнать ответ
❓Какое поведение неверное для defer
Anonymous Quiz
20%
Выполняется в порядке LIFO
10%
Может захватывать значения переменных при объявлении
52%
Работает даже после os.Exit()
11%
Не выполнится, если внутри go-рутины
6%
Узнать ответ
❓Сколько элементов хранится в одном bucket в map
Anonymous Quiz
10%
4
65%
8
4%
12
10%
16
12%
Узнать ответ
Ответ —
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❓ Что точно выведет программа на экран при запуске?
Учитывай, что используется default в select, и что между отправками и чтениями есть time.Sleep.
Хинт:Код показывает, как работает с при чтении из канала — если данных нет, выбирается default, не блокируя выполнение.
Ответ:
🔄 Что делает программа:
Одна горутина пишет 0, 1, 2 в канал ch с паузой 100мс, затем закрывает канал.
Вторая горутина читает из ch через select:
если данные есть → received: N
если нет → default case
если канал закрыт → channel closed
📤 Что выведет (примерно):
default case
default case
received: 0
default case
received: 1
default case
received: 2
channel closed
Порядок может немного отличаться из-за гонки между горутинами, но общая структура будет именно такая.
@golangtests
Учитывай, что используется default в select, и что между отправками и чтениями есть time.Sleep.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
done := make(chan struct{})
go func() {
defer close(done)
for i := 0; i < 3; i++ {
ch <- i
time.Sleep(100 * time.Millisecond)
}
close(ch)
}()
go func() {
for {
select {
case v, ok := <-ch:
if !ok {
fmt.Println("channel closed")
return
}
fmt.Println("received:", v)
default:
fmt.Println("default case")
time.Sleep(50 * time.Millisecond)
}
}
}()
<-done
time.Sleep(500 * time.Millisecond)
}
Хинт:
select
default
Ответ:
Одна горутина пишет 0, 1, 2 в канал ch с паузой 100мс, затем закрывает канал.
Вторая горутина читает из ch через select:
если данные есть → received: N
если нет → default case
если канал закрыт → channel closed
📤 Что выведет (примерно):
default case
default case
received: 0
default case
received: 1
default case
received: 2
channel closed
Порядок может немного отличаться из-за гонки между горутинами, но общая структура будет именно такая.
@golangtests
❓Вопрос:
Что будет выведено на экран? Напиши полный вывод программы и объясни, почему именно так.
💡Подсказки:
Что происходит с интерфейсами в Go при присвоении структур?
Что такое shadowing и как это влияет на s внутри анонимной функции?
Как работает передача аргументов в goroutine?
Как изменения структуры после передачи влияют на уже переданные значения?
✅ Ответ:
Hi, I'm Alice
Hi, I'm Bob
Hi, I'm Bob
@golangtests
Что будет выведено на экран? Напиши полный вывод программы и объясни, почему именно так.
package main
import (
"fmt"
"time"
)
type Speaker interface {
Speak() string
}
type Person struct {
name string
}
func (p Person) Speak() string {
return "Hi, I'm " + p.name
}
func main() {
var s Speaker
p := Person{name: "Alice"}
s = p
p.name = "Bob"
fmt.Println(s.Speak()) // (1)
func() {
s := p // shadowing: s — это теперь Person, а не Speaker
fmt.Println(s.Speak()) // (2)
}()
go func(p Person) {
time.Sleep(10 * time.Millisecond)
fmt.Println(p.Speak()) // (3)
}(p)
p.name = "Charlie"
time.Sleep(20 * time.Millisecond)
}
💡Подсказки:
Что такое shadowing и как это влияет на s внутри анонимной функции?
Как работает передача аргументов в goroutine?
Как изменения структуры после передачи влияют на уже переданные значения?
✅ Ответ:
Hi, I'm Bob
Hi, I'm Bob
@golangtests
go
package main
import (
"fmt"
)
func main() {
funcs := []func(){}
for i := 0; i < 3; i++ {
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for _, f := range funcs {
f()
}
}
❓ Варианты:
A)0 1 2
B)3 3 3
C) Паника на runtime
D) 0 0 0
💡 Пиши свой ответ в комментариях, и объясни почему!
✅ Правильный ответ:
🔍 Почему так происходит:
В этом коде создаётся срез из замыканий, и каждый func() внутри цикла ссылается на одну и ту же переменную i.
Ключевой момент: i не копируется при каждой итерации цикла, а продолжает изменяться, и все функции “запоминают” ссылку на одну и ту же i, а не её значение на момент создания.
К моменту вызова всех функций (f() в конце) цикл уже завершён, и значение i стало 3.
👉 Поэтому каждая функция выводит 3, а не 0, 1, 2.
@golangtests
Please open Telegram to view this post
VIEW IN TELEGRAM
🧪 Задача на Go 1.24: Range и поведение переменной цикла
Что выведет следующий код в Go 1.24?
Варианты ответа:
A)
B)
C)
D)
---
✅ Правильный ответ:A
Почему:
В Go 1.24 при использовании, переменная копируется на каждой итерации, а не переиспользуется. Таким образом, замыкания получают своё собственное значение на каждой итерации.
Здесь возвращает индексы ( , , ), а не значения среза.
Чтобы получить значения ( , , ), нужно использовать .
Что выведет следующий код в Go 1.24?
package main
import "fmt"
func main() {
values := []int{10, 20, 30}
funcs := []func(){}
for v := range values {
funcs = append(funcs, func() {
fmt.Println(v)
})
}
for _, f := range funcs {
f()
}
}
Варианты ответа:
A)
1
2
B)
2
2
C)
20
30
D)
0
0
---
✅ Правильный ответ:
Почему:
В Go 1.24 при использовании
for v := range
v
v
Здесь
range
0
1
2
Чтобы получить значения (
10
20
30
for _, v := range values
🧠 Что выведет следующий код?
Варианты ответа:
A)
B)
C)
D)
Код выведет:
changed: 20
defer: 10
main: 20
Объяснение:
main: Переменная num инициализируется значением 10.
change(&num): Вызывается функция change, и ей передается адрес переменной num (указатель на num). Теперь параметр val внутри change указывает на ту же ячейку памяти, где хранится num.
defer fmt.Println("defer:", *val): Внутри change встречается оператор defer.
Важно: Аргументы для отложенного вызова (*val в данном случае) вычисляются сразу в момент объявления defer, а не в момент выполнения отложенной функции. На этом этапе *val (значение по адресу, на который указывает val, то есть значение num) равно 10. Таким образом, вызов fmt.Println("defer:", 10) ставится в очередь на выполнение перед выходом из функции change.
*val = 20: Значение по адресу, на который указывает val, изменяется на 20. Поскольку val указывает на num, это напрямую изменяет значение переменной num в функции main на 20.
fmt.Println("changed:", *val): Выводится текущее значение по адресу val, которое теперь равно 20. Печатается changed: 20.
Конец change: Функция change собирается завершиться. Перед выходом выполняется отложенный вызов.
Выполнение defer: Выполняется ранее запланированный вызов fmt.Println("defer:", 10). Печатается defer: 10.
Возврат в main: Управление возвращается в main.
fmt.Println("main:", num): Выводится текущее значение переменной num. Так как функция change изменила его через указатель, num теперь равно 20. Печатается main: 20.
@golangtests
package main
import (
"fmt"
)
func change(val *int) {
defer fmt.Println("defer:", *val)
*val = 20
fmt.Println("changed:", *val)
}
func main() {
num := 10
change(&num)
fmt.Println("main:", num)
}
Варианты ответа:
A)
defer: 20
main: 20
B)
defer: 10
main: 20
C)
changed: 20
main: 20
D)
defer: 20
main: 20
Код выведет:
defer: 10
main: 20
Объяснение:
main: Переменная num инициализируется значением 10.
change(&num): Вызывается функция change, и ей передается адрес переменной num (указатель на num). Теперь параметр val внутри change указывает на ту же ячейку памяти, где хранится num.
defer fmt.Println("defer:", *val): Внутри change встречается оператор defer.
Важно: Аргументы для отложенного вызова (*val в данном случае) вычисляются сразу в момент объявления defer, а не в момент выполнения отложенной функции. На этом этапе *val (значение по адресу, на который указывает val, то есть значение num) равно 10. Таким образом, вызов fmt.Println("defer:", 10) ставится в очередь на выполнение перед выходом из функции change.
*val = 20: Значение по адресу, на который указывает val, изменяется на 20. Поскольку val указывает на num, это напрямую изменяет значение переменной num в функции main на 20.
fmt.Println("changed:", *val): Выводится текущее значение по адресу val, которое теперь равно 20. Печатается changed: 20.
Конец change: Функция change собирается завершиться. Перед выходом выполняется отложенный вызов.
Выполнение defer: Выполняется ранее запланированный вызов fmt.Println("defer:", 10). Печатается defer: 10.
Возврат в main: Управление возвращается в main.
fmt.Println("main:", num): Выводится текущее значение переменной num. Так как функция change изменила его через указатель, num теперь равно 20. Печатается main: 20.
@golangtests
Задача: Что выведет следующий код при компиляции и запуске с использованием Go 1.24?
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
count := 3
fmt.Println("Запуск горутин...")
wg.Add(count)
for i := 0; i < count; i++ {
// Запускаем горутину в каждой итерации
go func() {
defer wg.Done()
// Имитируем небольшую работу
time.Sleep(time.Duration(10) * time.Millisecond)
// Используем переменную цикла 'i' внутри горутины
fmt.Printf("Горутина видит i = %d\n", i)
}()
}
fmt.Println("Ожидание завершения горутин...")
wg.Wait()
fmt.Println("Все горутины завершены.")
}
Разбор:
Когда горутины реально начинали выполняться (после небольшой задержки time.Sleep), цикл for, скорее всего, уже завершался. К этому моменту переменная i имела бы свое конечное значение (в данном случае 3, так как цикл завершается, когда i становится равным count).
Поэтому в старых версиях Go этот код, скорее всего, вывел бы:
Запуск горутин...
Ожидание завершения горутин...
Горутина видит i = 3
Горутина видит i = 3
Горутина видит i = 3
Все горутины завершены.
(Порядок строк "Горутина видит..." мог быть разным). Чтобы обойти это, раньше приходилось делать так: i := i внутри цикла перед запуском горутины, чтобы создать копию переменной для каждой итерации.
Новое поведение (Go 1.22 и новее, включая 1.24): Начиная с Go 1.22, семантика переменных цикла for была изменена для предотвращения этой распространенной ошибки. Теперь переменная цикла (i в нашем случае) пересоздается для каждой итерации.
Это означает, что каждая горутина захватывает свою собственную копию i, соответствующую значению на момент этой итерации.
Ожидаемый вывод (Go 1.24): Благодаря изменению в Go 1.22, каждая горутина теперь корректно видит значение i той итерации, в которой она была запущена. Поэтому вывод будет (порядок строк "Горутина видит..." может варьироваться из-за недетерминированного планирования горутин):
Запуск горутин...
Ожидание завершения горутин...
Горутина видит i = 0
Горутина видит i = 1
Горутина видит i = 2
Все горутины завершены.
Use code with caution.
Или, например:
Запуск горутин...
Ожидание завершения горутин...
Горутина видит i = 2
Горутина видит i = 0
Горутина видит i = 1
Все горутины завершены.
Подвох заключается в том, что код выглядит как классический пример ошибки захвата переменной цикла, но из-за изменений в языке начиная с Go 1.22, он теперь работает "правильно" без необходимости явного копирования переменной (i := i).
Please open Telegram to view this post
VIEW IN TELEGRAM
go
package main
import "fmt"
// Пара обобщённого типа
type Pair[T any, U any] struct {
First T
Second U
}
// Метод, меняющий местами элементы
func (p Pair[T, U]) Swap() Pair[U, T] {
return Pair[U, T]{First: p.Second, Second: p.First}
}
// Карта обобщённого типа
type Mapping[K comparable, V any] map[K]V
func main() {
// явно указываем T=int, U=string
p1 := Pair[int, string]{First: 1, Second: "one"}
// начиная с Go 1.21 можно вывести параметры типа из литерала!
// здесь компилятор сам понимает, что T=string, U=int
p2 := Pair{"two", 2}
// аналогично для обобщённого alias-типа map
m := Mapping{"beta": 2}
// откатываем пару p2
swapped := p2.Swap()
fmt.Printf("%T %v\n", p2, p2)
fmt.Printf("%T %v\n", swapped, swapped)
fmt.Printf("%T %v\n", m, m)
}
Ответ: Код на Go 1.24 выведет следующее:
`main.Pair string int {two 2}`
`main.Pair int string {2 two}`
`main.Mapping string int map["beta":2]`
**Объяснение:**
1. **`p1 := Pairint, string{First: 1, Second: "one"}`** и **`p2 := Pair{"two", 2}`**:
* Создаются две переменные типа `Pair`.
* Для `p1` типы `T` (int) и `U` (string) указываются явно.
* Для `p2`, начиная с Go 1.21, компилятор автоматически выводит типы `T` (string) и `U` (int) из значений литерала `{"two", 2}`.
2. **`m := Mapping{"beta": 2}`**:
* Создается переменная `m` типа `Mapping`. `Mapping` является псевдонимом для `mapstringint`. Компилятор выводит типы ключа (string) и значения (int) из литерала `{"beta": 2}`.
3. **`swapped := p2.Swap()`**:
* Вызывается метод `Swap()` для `p2`. Метод `Swap()` возвращает новую структуру `Pair`, в которой типы `U` и `T` поменяны местами, а также значения полей `First` и `Second`. Таким образом, `swapped` будет иметь тип `Pairint, string` и значение `{2, "two"}`.
4. **`fmt.Printf("%T %v\n", p2, p2)`**:
* `%T` выводит тип переменной `p2`, который был выведен как `main.Pair string int`.
* `%v` выводит значение переменной `p2`, которое равно `{two 2}`.
5. **`fmt.Printf("%T %v\n", swapped, swapped)`**:
* `%T` выводит тип переменной `swapped`, который является результатом метода `Swap()` и равен `main.Pair int string`.
* `%v` выводит значение переменной `swapped`, которое равно `{2 two}`.
6. **`fmt.Printf("%T %v\n", m, m)`**:
* `%T` выводит тип переменной `m`, который является `main.Mapping string int`, что эквивалентно `mapstringint`.
* `%v` выводит значение переменной `m`, которое является картой `map["beta":2]`.
Таким образом, программа выведет тип и значение каждой из созданных и модифицированных переменных.
Please open Telegram to view this post
VIEW IN TELEGRAM