🤔 Какой интерфейс должен реализовывать тип, чтобы его можно было использовать в качестве ключа в map?
Anonymous Quiz
10%
fmt.Stringer
25%
hashable
54%
comparable
11%
keyable
Какие циклы есть в Go ?
Спросят с вероятностью 8%
Существует один основной цикл — это цикл for. н может использоваться в различных формах, выполняя функции традиционных циклов
Формы цикла
1️⃣С тремя выражениями:
В этом примере классический цикл
2️⃣Как `while`:
В данном случае цикл
3️⃣Бесконечный:
Бесконечный цикл создается с использованием
4️⃣ С использованием range :
Цикл
Примеры:
1️⃣Итерация по массиву:
2️⃣Итерация по карте:
3️⃣Итерация по строке:
Есть только один основной цикл —
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Спросят с вероятностью 8%
Существует один основной цикл — это цикл for. н может использоваться в различных формах, выполняя функции традиционных циклов
while
, do-while
и классического for
.Формы цикла
1️⃣С тремя выражениями:
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
}
В этом примере классический цикл
for
состоит из трех частей: инициализация (i := 0
), условие (i < 5
) и инкремент (i++
). Этот формат аналогичен циклу for
в других языках программирования, таких как C или Java.2️⃣Как `while`:
package main
import "fmt"
func main() {
i := 0
for i < 5 {
fmt.Println(i)
i++
}
}
В данном случае цикл
for
используется как while
. Условие (i < 5
) проверяется перед каждой итерацией, и цикл продолжается, пока условие истинно.3️⃣Бесконечный:
package main
import "fmt"
func main() {
i := 0
for {
if i >= 5 {
break
}
fmt.Println(i)
i++
}
}
Бесконечный цикл создается с использованием
for
без условий. Для выхода из такого цикла необходимо использовать операторы break
или return
.4️⃣ С использованием range :
package main
import "fmt"
func main() {
arr := []int{1, 2, 3, 4, 5}
for index, value := range arr {
fmt.Printf("Index: %d, Value: %d\n", index, value)
}
}
Цикл
for
с использованием range
позволяет итерироваться по элементам массивов, срезов, карт, строк и каналов. В данном примере index
представляет индекс текущего элемента, а value
— его значение.Примеры:
1️⃣Итерация по массиву:
arr := [5]int{10, 20, 30, 40, 50}
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
2️⃣Итерация по карте:
m := map[string]int{"a": 1, "b": 2, "c": 3}
for key, value := range m {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
3️⃣Итерация по строке:
s := "hello"
for index, char := range s {
fmt.Printf("Index: %d, Char: %c\n", index, char)
}
Есть только один основной цикл —
for
, который можно использовать как классический for
, while
, бесконечный цикл или цикл по коллекциям с range
. Этот подход обеспечивает гибкость и простоту написания циклов в различных ситуациях.👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
🤔 Какой метод нужно реализовать, чтобы структура удовлетворяла интерфейсу fmt.Stringer?
Anonymous Quiz
21%
ToString() string
10%
Format() string
64%
String() string
5%
Print() string
Как работать со слайсами ?
Спросят с вероятностью 8%
Работа со слайсами является важной частью, поскольку слайсы широко используются для работы с последовательностями данных. Давайте разберем, что такое слайсы, почему они важны, и как с ними работать, с примерами кода.
Что это такое?
Слайс — это динамическая последовательность элементов одного типа. В отличие от массивов, они имеют гибкий размер, который может изменяться во время выполнения программы. Основаны на массивах, но предоставляют гораздо более удобные возможности для работы с последовательностями данных.
Основные операции:
Существует несколько способов создания:
1️⃣Создание слайса из массива:
2️⃣Создание слайса с помощью встроенной функции `make`:
3️⃣Создание слайса литералом:
Изменение размера слайса
С помощью функции
Доступ к элементам слайса и изменение их
Аналогичны работе с массивами:
Итерация по слайсу
Выполняется с помощью цикла
Копирование
Для этого используется функция
Особенности
✅Емкость и длина: Он имеет два атрибута: длину (количество элементов) и емкость (максимальное количество элементов, которое может быть размещено без выделения новой памяти).
✅Срез (slicing): Можно создавать новые слайсы из существующих.
Слайсы — это гибкие и удобные структуры данных для работы с последовательностями элементов. Они обеспечивают простое создание, изменение размера, доступ к элементам и итерацию по ним. Благодаря встроенным функциям, таким как
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Спросят с вероятностью 8%
Работа со слайсами является важной частью, поскольку слайсы широко используются для работы с последовательностями данных. Давайте разберем, что такое слайсы, почему они важны, и как с ними работать, с примерами кода.
Что это такое?
Слайс — это динамическая последовательность элементов одного типа. В отличие от массивов, они имеют гибкий размер, который может изменяться во время выполнения программы. Основаны на массивах, но предоставляют гораздо более удобные возможности для работы с последовательностями данных.
Основные операции:
Существует несколько способов создания:
1️⃣Создание слайса из массива:
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // содержит элементы с индексами 1, 2, 3
fmt.Println(slice) // [2 3 4]
2️⃣Создание слайса с помощью встроенной функции `make`:
slice := make([]int, 5) // слайс из 5 элементов, инициализированных нулями
fmt.Println(slice) // [0 0 0 0 0]
3️⃣Создание слайса литералом:
slice := []int{1, 2, 3, 4, 5}
fmt.Println(slice) // [1 2 3 4 5]
Изменение размера слайса
С помощью функции
append
:slice := []int{1, 2, 3}
slice = append(slice, 4, 5) // добавляем элементы 4 и 5 в конец слайса
fmt.Println(slice) // [1 2 3 4 5]
Доступ к элементам слайса и изменение их
Аналогичны работе с массивами:
slice := []int{1, 2, 3}
fmt.Println(slice[1]) // 2
slice[1] = 20
fmt.Println(slice) // [1 20 3]
Итерация по слайсу
Выполняется с помощью цикла
for
:slice := []int{1, 2, 3, 4, 5}
for i, v := range slice {
fmt.Printf("Index: %d, Value: %d\n", i, v)
}
Копирование
Для этого используется функция
copy
:src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println(dst) // [1 2 3]
Особенности
✅Емкость и длина: Он имеет два атрибута: длину (количество элементов) и емкость (максимальное количество элементов, которое может быть размещено без выделения новой памяти).
slice := make([]int, 3, 5) // длина 3, емкость 5
fmt.Println(len(slice)) // 3
fmt.Println(cap(slice)) // 5
✅Срез (slicing): Можно создавать новые слайсы из существующих.
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:4]
fmt.Println(newSlice) // [2 3 4]
Слайсы — это гибкие и удобные структуры данных для работы с последовательностями элементов. Они обеспечивают простое создание, изменение размера, доступ к элементам и итерацию по ним. Благодаря встроенным функциям, таким как
append
и copy
, работа со слайсами становится ещё проще.👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
👾 349 вопросов собесов на Golang Developer
🔒 База реальных собесов
🔒 База тестовых заданий
👾 Список менторов
👣 Golang
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 С/С++
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 PHP
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
🖥 Frontend
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
🖥 Тестировщик
├ Вопросы собесов
├ Вакансии
└ Тесты
🖥 Python
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 Java
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 Kotlin
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 С#
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
👩💻 Swift
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
🖥 Data Science
├ Вопросы собесов
├ Вакансии
└ Тесты
👩💻 DevOps
├ Вопросы собесов
├ Вакансии
└ Тесты
⚙ Backend
└ Вопросы собесов
👾 Список менторов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
├ LeetCode ответы
└ Тесты
├ Вопросы собесов
├ Вакансии
└ Тесты
├ Вопросы собесов
├ Вакансии
└ Тесты
└ Вопросы собесов
Please open Telegram to view this post
VIEW IN TELEGRAM
Golang | Вопросы собесов pinned «👾 349 вопросов собесов на Golang Developer 🔒 База реальных собесов 🔒 База тестовых заданий 👾 Список менторов 👣 Golang ├ Вакансии ├ LeetCode ответы └ Тесты 👩💻 С/С++ ├ Вопросы собесов ├ Вакансии ├ LeetCode ответы └ Тесты 👩💻 PHP ├ Вопросы собесов ├ Вакансии…»
🤔 Какое ключевое слово используется для объявления неименованного канала в Go?
Anonymous Quiz
7%
channel
72%
chan
15%
make
6%
new
Что такое указатели ?
Спросят с вероятностью 8%
Указатели представляют собой переменные, которые хранят адреса других переменных. Это означает, что вместо того, чтобы хранить значение непосредственно, указатель хранит место в памяти, где находится это значение.
Зачем они нужны?
1️⃣Эффективность:
✅Указатели позволяют передавать большие структуры данных в функции без необходимости копирования. Вместо этого передается адрес структуры, что экономит память и время выполнения.
2️⃣Модификация данных:
✅Указатели позволяют функциям изменять значения переменных, передаваемых им в качестве аргументов. Это позволяет создавать более гибкие и мощные функции.
3️⃣Создание сложных структур данных:
✅Указатели используются для создания ссылочных типов данных, таких как связные списки, деревья и графы.
Как их использовать?
1️⃣Создание и использование:
Здесь переменная
2️⃣Функции:
В данном примере функция
3️⃣Использование со структурами:
В этом примере функция
Преимущества:
✅Эффективность работы с памятью: Указатели позволяют передавать данные без копирования, что улучшает производительность.
✅Гибкость в изменении данных: Указатели позволяют функциям изменять переданные им данные.
✅Поддержка сложных структур данных: Указатели необходимы для создания динамических структур данных.
Недостатки:
✅Сложность управления памятью: Неправильное использование указателей может привести к утечкам памяти и ошибкам, таким как разыменование нулевого указателя.
✅Усложнение кода: Работа с указателями может сделать код менее читаемым и трудным для отладки.
Указатели — это переменные, которые хранят адреса других переменных. Они помогают эффективно управлять памятью и позволяют функциям изменять переданные им данные. Однако неправильное использование указателей может привести к ошибкам.
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Спросят с вероятностью 8%
Указатели представляют собой переменные, которые хранят адреса других переменных. Это означает, что вместо того, чтобы хранить значение непосредственно, указатель хранит место в памяти, где находится это значение.
Зачем они нужны?
1️⃣Эффективность:
✅Указатели позволяют передавать большие структуры данных в функции без необходимости копирования. Вместо этого передается адрес структуры, что экономит память и время выполнения.
2️⃣Модификация данных:
✅Указатели позволяют функциям изменять значения переменных, передаваемых им в качестве аргументов. Это позволяет создавать более гибкие и мощные функции.
3️⃣Создание сложных структур данных:
✅Указатели используются для создания ссылочных типов данных, таких как связные списки, деревья и графы.
Как их использовать?
1️⃣Создание и использование:
package main
import "fmt"
func main() {
var x int = 10
var p *int // Объявление указателя на int
p = &x // Присваивание указателю адреса переменной x
fmt.Println("Value of x:", x) // Output: 10
fmt.Println("Address of x:", p) // Вывод адреса x
fmt.Println("Value via p:", *p) // Разыменование указателя, Output: 10
}
Здесь переменная
p
является указателем на int
и хранит адрес переменной x
. Разыменование указателя (*p
) позволяет получить значение, хранящееся по этому адресу.2️⃣Функции:
package main
import "fmt"
func main() {
x := 10
fmt.Println("Before:", x) // Output: 10
increment(&x)
fmt.Println("After:", x) // Output: 11
}
func increment(p *int) {
*p++ // Увеличение значения по адресу, на который указывает p
}
В данном примере функция
increment
принимает указатель на int
и увеличивает значение по этому адресу. Это позволяет изменять значение переменной x
непосредственно.3️⃣Использование со структурами:
package main
import "fmt"
type Person struct {
name string
age int
}
func main() {
p := Person{name: "Alice", age: 30}
fmt.Println("Before:", p) // Output: {Alice 30}
updatePerson(&p)
fmt.Println("After:", p) // Output: {Alice 31}
}
func updatePerson(p *Person) {
p.age++ // Изменение поля структуры через указатель
}
В этом примере функция
updatePerson
изменяет поле структуры Person
через указатель на эту структуру.Преимущества:
✅Эффективность работы с памятью: Указатели позволяют передавать данные без копирования, что улучшает производительность.
✅Гибкость в изменении данных: Указатели позволяют функциям изменять переданные им данные.
✅Поддержка сложных структур данных: Указатели необходимы для создания динамических структур данных.
Недостатки:
✅Сложность управления памятью: Неправильное использование указателей может привести к утечкам памяти и ошибкам, таким как разыменование нулевого указателя.
✅Усложнение кода: Работа с указателями может сделать код менее читаемым и трудным для отладки.
Указатели — это переменные, которые хранят адреса других переменных. Они помогают эффективно управлять памятью и позволяют функциям изменять переданные им данные. Однако неправильное использование указателей может привести к ошибкам.
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
🤔 Какой тип должен реализовывать метод Error() string?
Anonymous Quiz
57%
error
7%
fmt.Stringer
11%
string
26%
fmt.Error
Что будет в Map, если не делать make или short assign ?
Спросят с вероятностью 8%
Карты (maps) необходимо инициализировать перед использованием. Если карта не была инициализирована с помощью функции
Пример с неинициализированной картой
Этот код приведет к панике с сообщением об ошибке:
Инициализация карты
Чтобы избежать паники, карту необходимо инициализировать перед использованием. Есть 2 способа:
1️⃣Использование функции `make`:
2️⃣Использование литерала карты:
Пример:
Если карта не была инициализирована с помощью
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Спросят с вероятностью 8%
Карты (maps) необходимо инициализировать перед использованием. Если карта не была инициализирована с помощью функции
make
или литерала карты, она будет иметь нулевое значение nil
. Попытка добавить элементы в такую карту приведет к панике (panic
).Пример с неинициализированной картой
package main
import "fmt"
func main() {
var myMap map[string]int
// Карта не инициализирована, её значение - nil
fmt.Println(myMap) // Output: map[]
// Попытка добавить элемент в неинициализированную карту
// Это вызовет панику
myMap["key"] = 1
}
Этот код приведет к панике с сообщением об ошибке:
panic: assignment to entry in nil map
Инициализация карты
Чтобы избежать паники, карту необходимо инициализировать перед использованием. Есть 2 способа:
1️⃣Использование функции `make`:
package main
import "fmt"
func main() {
// Инициализация карты с помощью make
myMap := make(map[string]int)
myMap["key"] = 1
fmt.Println(myMap) // Output: map[key:1]
}
2️⃣Использование литерала карты:
package main
import "fmt"
func main() {
// Инициализация карты с помощью литерала карты
myMap := map[string]int{
"key1": 1,
"key2": 2,
}
fmt.Println(myMap) // Output: map[key1:1 key2:2]
}
Пример:
package main
import "fmt"
func main() {
// Инициализация карты с помощью make
myMap := make(map[string]int)
// Добавление элементов в карту
myMap["one"] = 1
myMap["two"] = 2
// Вывод карты
fmt.Println(myMap) // Output: map[one:1 two:2]
// Доступ к элементу карты
value := myMap["one"]
fmt.Println("Value for key 'one':", value) // Output: Value for key 'one': 1
// Проверка наличия ключа в карте
if val, exists := myMap["three"]; exists {
fmt.Println("Key 'three' exists with value:", val)
} else {
fmt.Println("Key 'three' does not exist")
}
// Удаление элемента из карты
delete(myMap, "two")
fmt.Println(myMap) // Output: map[one:1]
}
Если карта не была инициализирована с помощью
make
или литерала карты, она будет nil
. Попытка добавить элементы в такую карту приведет к панике. Чтобы избежать этого, необходимо инициализировать карту перед использованием.👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Встроены мощные инструменты для написания и запуска тестов. Тестирование — важная часть разработки ПО, так как помогает убедиться, что код работает правильно и что изменения не приводят к регрессиям.
Основные компоненты
_test.go
. Это позволяет инструменту тестирования Go автоматически распознавать их как тесты.Test
и принимать один аргумент типа *testing.T
.// main.go
package main
func Add(a, b int) int {
return a + b
}
// main_test.go
package main
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
expected := 5
if result != expected {
t.Errorf("Add(2, 3) = %d; want %d", result, expected)
}
}
go test
в терминале. Она автоматически найдет и выполнит все тесты в текущем пакете.$ go test
// main_test.go
package main
import "testing"
func TestAdd(t *testing.T) {
tests := []struct {
a, b, expected int
}{
{1, 2, 3},
{0, 0, 0},
{-1, -1, -2},
{2, 2, 4},
}
for _, tt := range tests {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой интерфейс используется для записи данных в различные источники?
Anonymous Quiz
92%
io.Writer
4%
io.Reader
2%
io.Output
2%
io.Printer
Карты (maps) должны быть сравнимыми. Это означает, что типы, используемые в качестве ключей, должны поддерживать операции сравнения на равенство (
==
) и неравенство (!=
). Сравнимость ключей необходима для корректного функционирования карт, так как операции поиска, вставки и удаления требуют проверки на равенство ключей.int
, int8
, int16
, int32
, int64
, uint
, uint8
, uint16
, uint32
, uint64
):var intMap map[int]string
intMap = make(map[int]string)
intMap[1] = "one"
string
):var stringMap map[string]int
stringMap = make(map[string]int)
stringMap["one"] = 1
bool
):var boolMap map[bool]string
boolMap = make(map[bool]string)
boolMap[true] = "yes"
boolMap[false] = "no"
*int
, *struct
):var ptrMap map[*int]string
ptrMap = make(map[*int]string)
var a int
ptrMap[&a] = "pointer to a"
chan T
):var chanMap map[chan int]string
chanMap = make(map[chan int]string)
c := make(chan int)
chanMap[c] = "channel"
var ifaceMap map[interface{}]string
ifaceMap = make(map[interface{}]string)
ifaceMap[1] = "one"
ifaceMap["key"] = "value"
struct
), если все их поля сравнимы:type Person struct {
Name string
Age int
}
var structMap map[Person]string
structMap = make(map[Person]string)
structMap[Person{"Alice", 30}] = "person 1"
slice
):// Это вызовет ошибку компиляции
// var sliceMap map[[]int]string
map
):// Это вызовет ошибку компиляции
// var mapMap map[map[int]string]string
func
):// Это вызовет ошибку компиляции
// var funcMap map[func() int]string
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
// Карта с ключами типа int
intMap := make(map[int]string)
intMap[1] = "one"
intMap[2] = "two"
fmt.Println(intMap) // Output: map[1:one 2:two]
// Карта с ключами типа string
stringMap := make(map[string]int)
stringMap["one"] = 1
stringMap["two"] = 2
fmt.Println(stringMap) // Output: map[one:1 two:2]
// Карта с ключами типа bool
boolMap := make(map[bool]string)
boolMap[true] = "yes"
boolMap[false] = "no"
fmt.Println(boolMap) // Output: map[false:no true:yes]
// Карта с ключами типа *int
a, b := 1, 2
ptrMap := make(map[*int]string)
ptrMap[&a] = "pointer to a"
ptrMap[&b] = "pointer to b"
fmt.Println(ptrMap) // Output: map[0x...:pointer to a 0x...:pointer to b]
// Карта с ключами типа struct
structMap := make(map[Person]string)
structMap[Person{"Alice", 30}] = "person 1"
structMap[Person{"Bob", 25}] = "person 2"
fmt.Println(structMap) // Output: map[{Alice 30}:person 1 {Bob 25}:person 2]
}
Ключи должны быть сравнимыми, то есть поддерживать операции сравнения (
==
и !=
). Это включает целые числа, строки, булевы значения, указатели, каналы, интерфейсы (сравнимые) и структуры (если все их поля сравнимы). Срезы, карты и функции не могут быть использованы в качестве ключей.Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой метод используется для декодирования JSON данных в Go?
Anonymous Quiz
82%
Unmarshal
12%
Decode
5%
Parse
2%
Deserialize
Юнит-тесты (unit tests) — это тесты, предназначенные для проверки корректности работы отдельных модулей или единиц кода, таких как функции или методы. Основная цель юнит-тестов — убедиться, что каждый модуль кода работает как ожидается. Играют ключевую роль в поддержке качества и надежности кода.
Юнит-тесты помогают выявлять ошибки и проблемы в коде на самых ранних этапах разработки, что снижает затраты на их исправление.
Хорошо написанные юнит-тесты служат живой документацией для кода, показывая, как именно должны работать функции и методы.
Наличие юнит-тестов делает процесс рефакторинга безопаснее, так как тесты помогают убедиться, что изменения в коде не нарушили его корректную работу.
Юнит-тесты обеспечивают уверенность в том, что код работает правильно, что особенно важно при добавлении новых функций или исправлении ошибок.
_test.go
.Test
и принимать один аргумент типа *testing.T
.Рассмотрим пример, где у нас есть функция, которая складывает два числа, и мы пишем для неё юнит-тест.
// main.go
package main
func Add(a, b int) int {
return a + b
}
// main_test.go
package main
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
expected := 5
if result != expected {
t.Errorf("Add(2, 3) = %d; want %d", result, expected)
}
}
Чтобы запустить юнит-тесты, используйте команду
go test
в терминале.$ go test
Table-driven tests позволяют легко добавлять новые тестовые случаи и улучшать читаемость тестов.
package main
import "testing"
func TestAdd(t *testing.T) {
tests := []struct {
a, b, expected int
}{
{1, 2, 3},
{0, 0, 0},
{-1, -1, -2},
{2, 2, 4},
}
for _, tt := range tests {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
}
}
}
Лучшие практики
Каждый юнит-тест должен проверять только одну конкретную функцию или метод и проверять один аспект её поведения.
Имена тестовых функций должны быть понятными и отражать их цель. Например,
TestAdd
для тестирования функции Add
.Убедитесь, что ваши тесты проверяют крайние случаи и потенциальные ошибки, такие как нулевые значения, отрицательные числа и переполнения.
Регулярно запускайте тесты, особенно перед коммитами и релизами, чтобы убедиться в отсутствии регрессий.
При тестировании функций, которые зависят от внешних ресурсов (таких как базы данных или API), используйте мокирование (mocking) для изоляции тестов.
Юнит-тесты проверяют отдельные функции или методы на корректность их работы. Они помогают выявлять ошибки на ранней стадии, служат документацией и поддерживают безопасный рефакторинг кода. Пишутся в файлах с суффиксом
_test.go
и запускаются с помощью команды go test
.Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой метод используется для чтения содержимого файла в Go?
Anonymous Quiz
44%
Read
38%
ReadFile
17%
Open
1%
Load
Срезы (slices) — это динамические массивы, которые могут изменять свой размер. Встроенная функция
append
используется для добавления новых элементов к срезу. Основные особенности:
Могут увеличивать свой размер динамически. Когда вызывается функция
append
, если подлежащий массив не имеет достаточной емкости для размещения новых элементов, создается новый массив, и все существующие элементы копируются в него.Функция
append
изменяет длину среза, добавляя новые элементы. Емкость может также увеличиваться, если требуется больше памяти для новых элементов.append
возвращает новый срез, который включает добавленные элементы. Этот новый срез может указывать на новый массив, если емкость исходного была недостаточной.Пример:
package main
import "fmt"
func main() {
// Создание пустого среза
var s []int
// Добавление одного элемента
s = append(s, 1)
fmt.Println(s) // Output: [1]
// Добавление нескольких элементов
s = append(s, 2, 3, 4)
fmt.Println(s) // Output: [1 2 3 4]
// Добавление элементов из другого среза
t := []int{5, 6, 7}
s = append(s, t...)
fmt.Println(s) // Output: [1 2 3 4 5 6 7]
}
Проверяется, достаточно ли емкости в подлежащем массиве для размещения новых элементов. Емкость (
capacity
) среза — это размер подлежащего массива, который может быть больше, чем текущая длина (length
) среза.Если емкости недостаточно, выделяется новый массив, обычно в два раза больший, чем текущий размер.
Все существующие элементы копируются в новый массив, и новые элементы добавляются в конец.
Новый срез, указывающий на новый массив, возвращается.
Пример:
package main
import "fmt"
func main() {
// Изначальный срез с длиной 0 и емкостью 0
s := []int{}
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
// Добавление элементов и отслеживание изменений длины и емкости
for i := 1; i <= 10; i++ {
s = append(s, i)
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
}
В этом примере, когда вы добавляете элементы, емкость среза автоматически увеличивается. Вывод показывает, как длина и емкость изменяются с добавлением каждого нового элемента.
Функция
append
добавляет новые элементы к срезу, изменяя его длину. Если емкости подлежащего массива недостаточно, создается новый массив, в который копируются все элементы. Она возвращает новый срез, который может указывать на новый массив, если емкость была увеличена.Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой пакет используется для работы с регулярными выражениями в Go?
Anonymous Quiz
42%
regexp
38%
regex
10%
re
10%
reg
Интеграционные тесты — это тесты, которые проверяют взаимодействие между различными компонентами системы. В отличие от юнит-тестов, которые фокусируются на проверке отдельных функций или методов, интеграционные проверяют, как компоненты работают вместе, обеспечивая целостность и корректность всей системы.
Интеграционные тесты помогают убедиться, что различные части системы правильно взаимодействуют друг с другом. Это важно для выявления проблем на границах между компонентами, которые могут не проявиться в юнит-тестах.
Такие тесты помогают обнаруживать ошибки, возникающие при объединении модулей. Это могут быть проблемы с форматами данных, неправильное использование интерфейсов и другие ошибки, связанные с интеграцией.
Интеграционные тесты могут включать сценарии, приближенные к реальным условиям эксплуатации системы, что позволяет убедиться, что система работает правильно в реальной среде.
Интеграционные тесты могут требовать наличия нескольких зависимостей, таких как база данных, внешние API или другие сервисы. Настройте тестовую среду, которая будет эмулировать реальную среду.
Рассмотрим пример интеграционного теста для приложения, которое работает с базой данных. В этом примере мы будем тестировать функции создания и получения пользователя.
// main.go
package main
import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
"log"
)
type User struct {
ID int
Name string
}
func CreateUser(db *sql.DB, name string) (int, error) {
res, err := db.Exec("INSERT INTO users(name) VALUES(?)", name)
if err != nil {
return 0, err
}
id, err := res.LastInsertId()
if err != nil {
return 0, err
}
return int(id), nil
}
func GetUser(db *sql.DB, id int) (User, error) {
var user User
err := db.QueryRow("SELECT id, name FROM users WHERE id = ?", id).Scan(&user.ID, &user.Name)
if err != nil {
return user, err
}
return user, nil
}
func main() {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
_, err = db.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
if err != nil {
log.Fatal(err)
}
}
// main_test.go
package main
import (
"database/sql"
"testing"
_ "github.com/mattn/go-sqlite3"
)
func setupTestDB(t *testing.T) *sql.DB {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatal(err)
}
_, err = db.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
if err != nil {
t.Fatal(err)
}
return db
}
func TestCreateAndGetUser(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
// Создание пользователя
userID, err := CreateUser(db, "John Doe")
if err != nil {
t.Fatalf("Failed to create user: %v", err)
}
// Получение пользователя
user, err := GetUser(db, userID)
if err != nil {
t.Fatalf("Failed to get user: %v", err)
}
// Проверка результатов
if user.Name != "John Doe" {
t.Errorf("Expected name to be 'John Doe', got %s", user.Name)
}
}
Интеграционные тесты проверяют, как различные компоненты системы работают вместе. Они помогают выявлять ошибки на границах между модулями и обеспечивают целостность системы. Пишутся аналогично юнит-тестам, но включают взаимодействие между компонентами и часто требуют настройки тестовой среды.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какое ключевое слово в Go используется для создания именованных типов, которые могут быть основой для методов?
Anonymous Quiz
6%
new
59%
type
21%
struct
14%
interface
Что будет, если подставить переменную в массив ?
Спросят с вероятностью 8%
Подстановка переменной в массив происходит путем присвоения значения элементу массива. Они имеют фиксированный размер, который задается при их объявлении, и все элементы массива должны быть одного типа.
Пример использования:
В этом примере:
1️⃣Мы объявляем массив
2️⃣Создаем переменную
3️⃣Подставляем значение переменной
4️⃣Выводим массив, чтобы увидеть результат.
Изменение элементов
Массивы индексируются с нуля, и доступ к элементам массива осуществляется с использованием квадратных скобок
Переменные также могут использоваться для индексов массива:
Массивы могут содержать структуры. Рассмотрим пример с массивом структур:
Подстановка переменной в массив происходит через присваивание значения элементу массива по индексу. Массивы имеют фиксированный размер и могут содержать элементы одного типа. Можно также использовать переменные для индексов массива и работать с массивами структур.
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых
Спросят с вероятностью 8%
Подстановка переменной в массив происходит путем присвоения значения элементу массива. Они имеют фиксированный размер, который задается при их объявлении, и все элементы массива должны быть одного типа.
Пример использования:
package main
import "fmt"
func main() {
// Объявление и инициализация массива
var arr [5]int
// Переменная, значение которой будет подставлено в массив
value := 10
// Подставляем значение переменной в массив
arr[0] = value
// Вывод массива
fmt.Println(arr) // Output: [10 0 0 0 0]
}
В этом примере:
1️⃣Мы объявляем массив
arr
из 5 целых чисел (int
), изначально инициализированных нулями.2️⃣Создаем переменную
value
и присваиваем ей значение 10.3️⃣Подставляем значение переменной
value
в первый элемент массива arr
с индексом 0.4️⃣Выводим массив, чтобы увидеть результат.
Изменение элементов
Массивы индексируются с нуля, и доступ к элементам массива осуществляется с использованием квадратных скобок
[]
. Можно изменять значения элементов массива, присваивая им новые значения через соответствующие индексы:package main
import "fmt"
func main() {
// Объявление и инициализация массива
arr := [5]int{1, 2, 3, 4, 5}
// Переменные для подстановки
value1 := 10
value2 := 20
// Подстановка значений переменных в массив
arr[1] = value1
arr[3] = value2
// Вывод массива
fmt.Println(arr) // Output: [1 10 3 20 5]
}
Переменные также могут использоваться для индексов массива:
package main
import "fmt"
func main() {
// Объявление и инициализация массива
arr := [5]int{1, 2, 3, 4, 5}
// Переменные для индексов
idx1 := 2
idx2 := 4
// Подстановка значений в массив по индексам
arr[idx1] = 30
arr[idx2] = 50
// Вывод массива
fmt.Println(arr) // Output: [1 2 30 4 50]
}
Массивы могут содержать структуры. Рассмотрим пример с массивом структур:
package main
import "fmt"
// Определение структуры
type Person struct {
Name string
Age int
}
func main() {
// Объявление массива структур
var people [3]Person
// Переменная структуры
p := Person{Name: "Alice", Age: 30}
// Подстановка структуры в массив
people[0] = p
// Прямое присвоение структуры в массив
people[1] = Person{Name: "Bob", Age: 25}
people[2] = Person{Name: "Charlie", Age: 35}
// Вывод массива структур
fmt.Println(people)
// Output: [{Alice 30} {Bob 25} {Charlie 35}]
}
Подстановка переменной в массив происходит через присваивание значения элементу массива по индексу. Массивы имеют фиксированный размер и могут содержать элементы одного типа. Можно также использовать переменные для индексов массива и работать с массивами структур.
👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 349 вопроса на Golang разработчика. Ставь 👍 если нравится контент
🔐 База собесов | 🔐 База тестовых