Слайсы представляют собой мощный и гибкий инструмент для работы с последовательностями элементов. Основаны на массивах, но они предоставляют более удобный и динамичный способ работы с данными.
Указатель на первый элемент массива, на который ссылается слайс.
Количество элементов, доступных в слайсе.
Максимальное количество элементов, которое может содержать слайс без перераспределения памяти.
Можно представить в виде структуры
type slice struct {
ptr *ElementType // Указатель на базовый массив
len int // Длина
cap int // Емкость
}
Можно создать из массива, указав диапазон элементов:
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // Слайс содержит элементы с индексами 1, 2, 3
fmt.Println(slice) // [2 3 4]
}
Позволяет создать слайс определенной длины и емкости:
package main
import "fmt"
func main() {
slice := make([]int, 3, 5) // Слайс длиной 3 и емкостью 5
fmt.Println(slice) // [0 0 0]
}
Осуществляется так же, как и к элементам массива:
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Println(slice[0]) // 1
slice[1] = 10
fmt.Println(slice) // [1 10 3 4 5]
}
Для этого используется функция
append
package main
import "fmt"
func main() {
slice := []int{1, 2, 3}
slice = append(slice, 4, 5) // Добавляем элементы 4 и 5 в конец слайса
fmt.Println(slice) // [1 2 3 4 5]
}
Можно создавать новые слайсы на основе существующих
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5}
subSlice := slice[1:4] // Слайс содержит элементы с индексами 1, 2, 3
fmt.Println(subSlice) // [2 3 4]
}
Для этого используется функция
copy
package main
import "fmt"
func main() {
src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println(dst) // [1 2 3]
}
Могут автоматически изменять свою емкость при добавлении новых элементов с помощью
append
. Когда емкость текущего массива недостаточна для добавления новых элементов, создается новый массив с большей емкостью, в который копируются существующие элементы.package main
import "fmt"
func main() {
slice := make([]int, 3, 5)
fmt.Println("Before append:", slice, "Len:", len(slice), "Cap:", cap(slice))
slice = append(slice, 1, 2, 3)
fmt.Println("After append:", slice, "Len:", len(slice), "Cap:", cap(slice))
slice = append(slice, 4)
fmt.Println("After another append:", slice, "Len:", len(slice), "Cap:", cap(slice))
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
2. Литералы: для статических данных можно использовать литералы, например, map[string]int{"key": 1}.
3. Всегда проверяйте существование элемента с помощью value, ok := map[key], чтобы избежать ошибок доступа к несуществующим ключам.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Функция append используется для добавления элементов к слайсу. Эта функция может увеличивать длину слайса и, при необходимости, выделять новый подлежащий массив, если текущий массив не имеет достаточной емкости для хранения новых элементов.
Если текущий подлежащий массив слайса имеет достаточно места (емкости) для добавления новых элементов,
append
просто добавляет элементы к существующему массиву.Если емкость текущего массива недостаточна для размещения новых элементов,
append
выделяет новый массив, копирует в него существующие элементы и добавляет новые элементы. Новый массив будет иметь увеличенную емкость (как правило, в два раза больше, чем предыдущая).Синтаксис
slice = append(slice, elem1, elem2, ...)
Пример использования
package main
import "fmt"
func main() {
// Создаем слайс из 3 целых чисел
slice := []int{1, 2, 3}
// Добавляем один элемент
slice = append(slice, 4)
// Добавляем несколько элементов
slice = append(slice, 5, 6, 7)
// Выводим слайс
fmt.Println(slice) // Выводит: [1 2 3 4 5 6 7]
}
Создаем слайс с тремя элементами
[1, 2, 3]
.slice := []int{1, 2, 3}
Добавляем элемент
4
к слайсу. Теперь слайс содержит [1, 2, 3, 4]
.slice = append(slice, 4)
Добавляем элементы
5
, 6
, и 7
. Теперь слайс содержит [1, 2, 3, 4, 5, 6, 7]
.slice = append(slice, 5, 6, 7)
Выводим слайс, который содержит
[1, 2, 3, 4, 5, 6, 7]
.fmt.Println(slice)
Работа с емкостью и длиной
package main
import "fmt"
func main() {
slice := []int{1, 2, 3}
fmt.Printf("Before append: len=%d cap=%d %v\n", len(slice), cap(slice), slice)
slice = append(slice, 4)
fmt.Printf("After append: len=%d cap=%d %v\n", len(slice), cap(slice), slice)
slice = append(slice, 5, 6, 7)
fmt.Printf("After multiple appends: len=%d cap=%d %v\n", len(slice), cap(slice), slice)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В Map поиск по ключу в среднем имеет сложность O(1) благодаря хешированию, но может ухудшиться до O(n) при большом количестве коллизий.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1😁1
Массивы представляют собой фиксированную последовательность элементов одного типа. Являются основополагающей структурой данных, на базе которой строятся более сложные структуры, такие как слайсы. Рассмотрим, как устроены массивы, их особенности, а также сравнение с другими структурами данных.
Размер массива задается при его объявлении и не может изменяться во время выполнения программы.
Все элементы массива имеют один и тот же тип.
В отличие от слайсов, массивы хранят свои элементы в непрерывном блоке памяти.
С указанием типа элементов и фиксированного размера. Это объявление создает массив из пяти целых чисел, инициализированных нулями.
var arr [5]int
Массивы могут быть инициализированы при объявлении
arr := [5]int{1, 2, 3, 4, 5}
Можно также инициализировать массив частично, оставив остальные элементы равными нулям:
arr := [5]int{1, 2}
Осуществляется с использованием индексов, начиная с 0
fmt.Println(arr[0]) // 1
arr[1] = 10
fmt.Println(arr[1]) // 10
Фиксирована и задается при его объявлении. Ее можно получить с помощью функции
len
fmt.Println(len(arr)) // 5
При присваивании одного массива другому копируются все элементы:
arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := arr1
arr2[0] = 10
fmt.Println(arr1) // [1 2 3 4 5]
fmt.Println(arr2) // [10 2 3 4 5]
При этом копируется весь массив:
func modifyArray(a [5]int) {
a[0] = 10
}
arr := [5]int{1, 2, 3, 4, 5}
modifyArray(arr)
fmt.Println(arr) // [1 2 3 4 5]
Массивы имеют фиксированный размер, тогда как слайсы динамичны.
Массивы могут быть более производительными для небольших коллекций данных из-за отсутствия накладных расходов на управление динамическими данными.
Использование массивов
package main
import (
"fmt"
)
func main() {
// Объявление и инициализация массива
arr := [5]int{1, 2, 3, 4, 5}
// Доступ к элементам
fmt.Println("First element:", arr[0]) // First element: 1
// Изменение элементов
arr[1] = 10
fmt.Println("Modified array:", arr) // Modified array: [1 10 3 4 5]
// Длина массива
fmt.Println("Length of array:", len(arr)) // Length of array: 5
// Копирование массива
arr2 := arr
arr2[0] = 20
fmt.Println("Original array:", arr) // Original array: [1 10 3 4 5]
fmt.Println("Copied array:", arr2) // Copied array: [20 10 3 4 5]
// Передача массива в функцию
modifyArray(arr)
fmt.Println("Array after modifyArray call:", arr) // Array after modifyArray call: [1 10 3 4 5]
}
func modifyArray(a [5]int) {
a[0] = 10
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Forwarded from easyoffer
easyoffer
Backend
Python | Вопросы
Python | Удалёнка
Python | LeetCode
Python | Тесты
Frontend | Вопросы
Frontend | Удалёнка
JavaScript | LeetCode
Frontend | Тесты
Java | Вопросы
Java | Удалёнка
Java | LeetCode
Java | Тесты
Тестировщик | Вопросы
Тестировщик | Удалёнка
Тестировщик | Тесты
Data Science | Вопросы
Data Science | Удалёнка
Data Science | Тесты
C# | Вопросы
C# | Удалёнка
C# | LeetCode
C# | Тесты
C/C++ | Вопросы
C/C++ | Удалёнка
C/C++ | LeetCode
C/C++ | Тесты
Golang | Вопросы
Golang | Удалёнка
Golang | LeetCode
Golang | Тесты
DevOps | Вопросы
DevOps | Удалёнка
DevOps | Тесты
PHP | Вопросы
PHP | Удалёнка
PHP | LeetCode
PHP | Тесты
Kotlin | Вопросы
Kotlin | Удалёнка
Kotlin | LeetCode
Kotlin | Тесты
Swift | Вопросы
Swift | Удалёнка
Swift | LeetCode
Swift | Тесты
Please open Telegram to view this post
VIEW IN TELEGRAM
2. Получение элемента: value, ok := map[key] — возвращает значение и флаг существования.
3. Удаление элемента: delete(map, key).
4. Итерация: for key, value := range map.
5. Проверка существования: с помощью ok из выражения value, ok := map[key].
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯2👀2👍1
Это гибкий и мощный инструмент для работы с последовательностями элементов. Они предоставляют более высокоуровневый интерфейс для работы с массивами. Рассмотрим, как с ними работать, почему они нужны и какие операции можно выполнять.
Это динамическая последовательность элементов одного типа, которая предоставляет доступ к части или всем элементам массива без копирования данных. Он содержит три компонента:
Указатель на массив.
Длина (количество элементов в слайсе).
Ёмкость (максимальное количество элементов, которые могут быть включены в слайс без перераспределения памяти).
Слайсы позволяют работать с массивами более гибко:
В отличие от массивов, длина слайса может изменяться.
Слайсы можно передавать в функции и возвращать из них, не копируя данные.
Предоставляют множество встроенных функций для работы с последовательностями данных.
Из массива
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // слайс содержит элементы {2, 3, 4}
Используя make
slice := make([]int, 5) // создаёт слайс длиной и ёмкостью 5, заполненный нулями
Литерал слайса
slice := []int{1, 2, 3, 4, 5}
Доступ к элементам
fmt.Println(slice[0]) // выводит первый элемент слайса
Изменение элементов
slice[1] = 10 // изменяет второй элемент слайса
Добавление элементов
slice = append(slice, 6, 7) // добавляет элементы 6 и 7 к слайсу
Срезка (slicing)
newSlice := slice[1:3] // создаёт новый слайс с элементами с 1-го по 3-й
Рассмотрим пример функции, которая добавляет элемент в слайс и возвращает новый слайс
package main
import "fmt"
func main() {
nums := []int{1, 2, 3}
nums = append(nums, 4) // добавление элемента
fmt.Println(nums) // выводит [1, 2, 3, 4]
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Карты (maps) не являются потокобезопасными. Это означает, что если несколько горутин пытаются одновременно читать и записывать данные в карту, могут возникнуть состояния гонки, приводящие к некорректным результатам или панике программы.
Позволяют контролировать доступ к карте, обеспечивая, что только одна горутина имеет доступ к карте в любой момент времени.
package main
import (
"fmt"
"sync"
)
type SafeMap struct {
m map[string]int
mux sync.Mutex
}
func (sm *SafeMap) Set(key string, value int) {
sm.mux.Lock()
defer sm.mux.Unlock()
sm.m[key] = value
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mux.Lock()
defer sm.mux.Unlock()
value, exists := sm.m[key]
return value, exists
}
func main() {
sm := SafeMap{m: make(map[string]int)}
sm.Set("Alice", 25)
value, exists := sm.Get("Alice")
if exists {
fmt.Println("Value:", value)
} else {
fmt.Println("Key not found")
}
}
Позволяют одновременный доступ для чтения нескольким горутинам, блокируя доступ для записи. Это улучшает производительность при частых операциях чтения.
package main
import (
"fmt"
"sync"
)
type SafeMap struct {
m map[string]int
mux sync.RWMutex
}
func (sm *SafeMap) Set(key string, value int) {
sm.mux.Lock()
defer sm.mux.Unlock()
sm.m[key] = value
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mux.RLock()
defer sm.mux.RUnlock()
value, exists := sm.m[key]
return value, exists
}
func main() {
sm := SafeMap{m: make(map[string]int)}
sm.Set("Alice", 25)
value, exists := sm.Get("Alice")
if exists {
fmt.Println("Value:", value)
} else {
fmt.Println("Key not found")
}
}
Предоставляет готовую реализацию потокобезопасной карты. Он полезен, когда нужна простая потокобезопасная карта без необходимости управлять блокировками вручную.
package main
import (
"fmt"
"sync"
)
func main() {
var sm sync.Map
// Запись значения
sm.Store("Alice", 25)
// Чтение значения
value, exists := sm.Load("Alice")
if exists {
fmt.Println("Value:", value)
} else {
fmt.Println("Key not found")
}
// Удаление значения
sm.Delete("Alice")
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Горутины в Go являются легковесными потоками управления, которые позволяют выполнять параллельные задачи более эффективно по сравнению с потоками операционной системы. Их ключевые преимущества включают:
Горутины потребляют значительно меньше памяти и ресурсов по сравнению с потоками ОС. Каждая горутина стартует с размером стека порядка 2 КБ, тогда как поток ОС требует гораздо большего размера стека (обычно несколько мегабайт).
Горутины управляются встроенным планировщиком Go, а не планировщиком ОС. Планировщик Go распределяет выполнение горутин по доступным потокам ОС, используя концепцию "M:N" (много горутин на несколько потоков).
Создание, синхронизация и управление горутинами намного проще благодаря встроенным средствам Go, таким как каналы (
channels
) и sync
-пакет. В то время как работа с потоками ОС требует дополнительных усилий для синхронизации (мьютексы, условные переменные и т.д.).Стек горутины автоматически увеличивается или уменьшается в зависимости от потребностей, что позволяет эффективно использовать память.
Синтаксис и использование горутин интуитивно понятны. Для запуска достаточно добавить
go
перед вызовом функции:package main
import (
"fmt"
"time"
)
func sayHello() {
for i := 0; i < 5; i++ {
fmt.Println("Hello")
time.Sleep(100 * time.Millisecond)
}
}
func main() {
go sayHello() // Запускаем горутину
fmt.Println("World")
time.Sleep(1 * time.Second) // Даем горутине время завершиться
}
Горутины позволяют эффективно использовать современные многоядерные процессоры благодаря встроенной конкурентной модели и поддержке параллелизма.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Концепции объектно-ориентированного программирования (ООП) реализованы несколько иначе, чем в традиционных ООП-языках, таких как Java или C++. Не использует классы, наследование и полиморфизм на основе классов в привычном понимании. Вместо этого он применяет интерфейсы, структуры и встраивание для достижения гибкости и мощи ООП.
Основной способ организации и капсуляции данных — это структуры (
structs
). Структуры объединяют данные в одну сущность, но в отличие от классов, они не включают определение методов внутри себя. Вместо этого методы определяются отдельно и ассоциируются со структурой через определение получателя метода.type Person struct {
Name string
Age int
}
func (p Person) Greet() string {
return "Hello, my name is " + p.Name
}
Реализуется через интерфейсы. Интерфейс — это набор сигнатур методов. Тип считается реализующим интерфейс, если он имеет все методы, указанные в интерфейсе. Важной особенностью интерфейсов в Go является то, что типы могут удовлетворять интерфейсам неявно, без специального объявления.
type Greeter interface {
Greet() string
}
func GreetSomeone(g Greeter) {
fmt.Println(g.Greet())
}
Один из способов реализации композиции — встраивание структур. Можно встроить одну структуру в другую, что позволяет делегировать часть работы встроенной структуре.
type Employee struct {
Person
Position string
}
func (e Employee) Work() string {
return e.Name + " is working as a " + e.Position
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
2. Через функцию make: s := make([]int, length, capacity).
3. Срезав массив: s := array[start:end].
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3
Это ситуация, когда несколько горутин (или потоков) находятся в состоянии ожидания друг друга, из-за чего выполнение программы останавливается. В Go deadlock может произойти при неправильной работе с каналами, мьютексами и другими механизмами синхронизации.
Если несколько горутин используют блокировки (например, через мьютексы), убедитесь, что все они захватывают их в одном и том же порядке.
func main() {
var mu1, mu2 sync.Mutex
go func() {
mu1.Lock()
defer mu1.Unlock()
mu2.Lock()
defer mu2.Unlock()
}()
go func() {
mu2.Lock()
defer mu2.Unlock()
mu1.Lock()
defer mu1.Unlock()
}()
}
Каналы должны всегда иметь возможность отправки и получения данных. Если одна сторона (отправитель или получатель) заблокирована навсегда, возникает deadlock.
func main() {
ch := make(chan int)
ch <- 42 // Deadlock, так как никто не читает из канала
}
Каналы нужно закрывать только со стороны отправителя, и только тогда, когда больше не будет отправок данных. Неправильное закрытие или отсутствие закрытия может привести к проблемам, включая deadlock.
ch := make(chan int)
close(ch) // Закрыт слишком рано
ch <- 42 // Паника
Иногда deadlock происходит, если горутина ждет сама себя.
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch) // Никогда не выполнится
}
Go позволяет избегать блокировок с помощью механизма тайм-аутов и оператора
select
. Если операция занимает слишком много времени, можно выполнить альтернативное действие.func main() {
ch := make(chan int)
select {
case data := <-ch:
fmt.Println("Получены данные:", data)
case <-time.After(1 * time.Second):
fmt.Println("Тайм-аут, завершение")
}
}
Go предоставляет утилиту
go run -race
, которая помогает выявлять гонки данных и другие проблемы, связанные с синхронизацией.go run -race main.go
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👾2
Ключи в map (карте) должны обладать определенными свойствами, чтобы быть допустимыми и корректно работать с хеш-таблицей. Важно понимать, что ключи должны поддерживать операцию сравнения и быть хешируемыми.
Ключи должны поддерживать операцию сравнения с использованием оператора
==
. Это необходимо для проверки равенства ключей при выполнении операций вставки, поиска и удаления в карте.Ключи должны быть хешируемыми. Это значит, что для ключей должна существовать функция, которая преобразует их в хеш-код. Хеш-код используется для определения позиции ключа в хеш-таблице.
Булевый тип (bool)
m := map[bool]string{
true: "Yes",
false: "No",
}
Целочисленные типы (int, int8, int16, int32, int64, а также их беззнаковые эквиваленты uint, uint8, uint16, uint32, uint64)
m := map[int]string{
1: "One",
2: "Two",
}
Числа с плавающей точкой (float32, float64)
m := map[float64]string{
1.1: "One point one",
2.2: "Two point two",
}
Строки (string)
m := map[string]int{
"Alice": 25,
"Bob": 30,
}
Составные типы (структуры, массивы), при условии, что все их поля также поддерживают сравнение с помощью оператора ==
type Key struct {
FirstName string
LastName string
}
m := map[Key]int{
{"Alice", "Smith"}: 1,
{"Bob", "Johnson"}: 2,
}
slice
)Срезы не поддерживают операцию сравнения с использованием оператора
==
(только сравнение с nil
).map
)Карты не поддерживают операцию сравнения.
func
)Функции не поддерживают операцию сравнения.
package main
import "fmt"
type Person struct {
FirstName string
LastName string
}
func main() {
// Создаем карту с ключами типа Person
m := make(map[Person]int)
// Вставляем значения в карту
m[Person{"Alice", "Smith"}] = 25
m[Person{"Bob", "Johnson"}] = 30
// Выводим значения из карты
fmt.Println(m[Person{"Alice", "Smith"}]) // Выводит: 25
fmt.Println(m[Person{"Bob", "Johnson"}]) // Выводит: 30
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
В Go дополнительный блок фигурных скобок
{}
в функции используется для ограничения области видимости переменных и улучшения читаемости кода. Это позволяет временно вводить переменные или выполнять локальные операции без влияния на остальную часть функции.Переменные, объявленные внутри блока
{}
, видимы только в пределах этого блока. Это полезно для временных переменных, которые не должны "загрязнять" основную область видимости функции.func processData() {
{
value := 42
fmt.Println("Внутренний блок, value =", value) // value доступна только здесь
}
// fmt.Println(value) // Ошибка: value не определена за пределами блока
}
С помощью блоков можно явно управлять временем жизни переменных, таких как файлы, соединения или буферы. Это особенно важно для ресурсов, которые необходимо закрыть или освободить.
func readFile() {
{
file, err := os.Open("example.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close() // Закроется при выходе из блока
// Работа с файлом
fmt.Println("Чтение файла")
}
// Здесь файл уже закрыт
}
В больших функциях дополнительный блок позволяет логически разделить код на части, делая его более понятным.
func main() {
{
// Работа с настройками
config := loadConfig()
fmt.Println("Конфигурация загружена:", config)
}
{
// Работа с данными
data := fetchData()
fmt.Println("Данные получены:", data)
}
}
Можно использовать дополнительные блоки для изоляции сложных кусков кода и последующего их упрощения.
func calculate() int {
result := 0
{
a := 10
b := 20
result = a + b
}
return result
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM