Golang | Вопросы собесов
4.54K subscribers
28 photos
1 video
802 links
Download Telegram
🤔 Как устроен слайс в Go ?

Слайсы представляют собой мощный и гибкий инструмент для работы с последовательностями элементов. Основаны на массивах, но они предоставляют более удобный и динамичный способ работы с данными.

🚩Структура

🟠Указатель на базовый массив
Указатель на первый элемент массива, на который ссылается слайс.
🟠Длина (length)
Количество элементов, доступных в слайсе.
🟠Емкость (capacity)
Максимальное количество элементов, которое может содержать слайс без перераспределения памяти.

🚩Внутреннее устройство

Можно представить в виде структуры
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]
}


🟠Слайс с использованием функции make
Позволяет создать слайс определенной длины и емкости:
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]
}


🟠Извлечение подмножества слайса (slicing)
Можно создавать новые слайсы на основе существующих
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
👍4
🤔 Какие бывают типы изоляции транзакций?

1. Read Uncommitted – транзакция читает несохраненные изменения других транзакций (грязное чтение).
2. Read Committed – транзакция видит только сохраненные изменения других транзакций.
3. Repeatable Read – транзакция видит одинаковые данные при повторных запросах, но возможны фантомные чтения.
4. Serializable – полный контроль над данными, транзакции выполняются последовательно, но снижается производительность.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2
🤔 Как устроен массив в Go?

Массивы представляют собой фиксированную последовательность элементов одного типа. Являются основополагающей структурой данных, на базе которой строятся более сложные структуры, такие как слайсы. Рассмотрим, как устроены массивы, их особенности, а также сравнение с другими структурами данных.

🚩Основные характеристики

🟠Фиксированный размер
Размер массива задается при его объявлении и не может изменяться во время выполнения программы.
🟠Тип элементов
Все элементы массива имеют один и тот же тип.
🟠Непосредственное хранение данных
В отличие от слайсов, массивы хранят свои элементы в непрерывном блоке памяти.

🟠Объявление массива
С указанием типа элементов и фиксированного размера. Это объявление создает массив из пяти целых чисел, инициализированных нулями.
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
👍2
🤔 Как эффективно склеивать множество строк?

Самый эффективный способ — избегать многократной конкатенации, особенно в цикле, потому что каждая операция создаёт новую строку. Вместо этого используют буферы или строчные сборщики, которые работают с выделенной памятью и собирают результат за один проход. Это снижает количество аллокаций и копирований.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Что такое репликация?

Это процесс копирования и поддержания данных в синхронном или асинхронном порядке между несколькими базами данных или серверами. Это позволяет данным быть доступными на различных серверах, что увеличивает доступность, устойчивость к сбоям и может улучшить производительность приложений за счёт распределения нагрузки на разные серверы или узлы.

🚩Цели

🟠Увеличение доступности данных
Позволяет системе продолжать работать даже при сбое одного или нескольких серверов. При наличии нескольких копий данных, система может переключиться на использование актуальной копии данных на другом сервере.

🟠Распределение нагрузки
Может помочь распределить запросы чтения между несколькими узлами, тем самым уменьшая нагрузку на один сервер и улучшая время отклика в приложениях.

🟠Геораспределение
Реплик в разных географических локациях может улучшить время доступа к данным для пользователей, которые находятся ближе к одной из реплик.

🟠Обеспечение безопасности данных
Данных на разные физические места уменьшает риски, связанные с потерей данных в случае катастроф.

🚩Типы

🟠Синхронная репликация
Данные одновременно записываются в основную и реплицированную базы данных. Транзакция считается завершенной только после успешной записи на всех репликах. Это обеспечивает высокую степень согласованности данных, но может снижать производительность из-за задержек, связанных с ожиданием подтверждения от всех реплик.

🟠Асинхронная репликация
Изменения данных первоначально записываются на основной сервер, и только после этого асинхронно передаются на репликационные серверы. Это метод быстрее, поскольку основная система не ждёт подтверждения от реплик перед завершением транзакции. Однако это также увеличивает риск несогласованности данных между репликами.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 В чём отличие длины и ёмкости у слайса?

1. Длина (len): количество элементов, содержащихся в слайсе.
2. Ёмкость (cap): максимальное количество элементов, которые слайс может вместить без перевыделения памяти.
3. При добавлении элементов с помощью append длина увеличивается, а если она превышает ёмкость, выделяется новый блок памяти с удвоенной ёмкостью.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Как ООП в Go реализовано?

Концепции объектно-ориентированного программирования (ООП) реализованы несколько иначе, чем в традиционных ООП-языках, таких как 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
🔥3💊1
🤔 Как прочитать строку в виде иероглифов, кириллицы и т.д.?

В Go строки хранятся в UTF-8, что позволяет корректно работать с символами любых языков (включая иероглифы, кириллицу и т.д.).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Через какой канал возможна проверка работы горутины?

В Go для проверки работы горутины часто используют каналы. Они позволяют передавать данные между горутинами и могут использоваться для сигнализации о состоянии выполнения горутины.

🚩Основные способы проверки работы горутины через каналы

🟠Односторонний канал для завершения горутины
Горутина может отправлять сигнал (например, true) в канал, чтобы уведомить о своем завершении.
func worker(done chan bool) {
fmt.Println("Работа началась...")
time.Sleep(2 * time.Second) // Имитация работы
fmt.Println("Работа завершена!")
done <- true // Отправляем сигнал в канал
}

func main() {
done := make(chan bool)

go worker(done) // Запускаем горутину

// Ожидаем сигнал завершения
<-done
fmt.Println("Основной поток: горутина завершена")
}


🟠Канал для передачи промежуточных результатов
Горутина может отправлять данные в канал, чтобы сигнализировать о прогрессе выполнения.
func worker(progress chan int) {
for i := 1; i <= 5; i++ {
fmt.Printf("Шаг %d выполнен\n", i)
progress <- i // Отправляем номер шага в канал
time.Sleep(500 * time.Millisecond) // Имитация работы
}
close(progress) // Закрываем канал после завершения работы
}

func main() {
progress := make(chan int)

go worker(progress) // Запускаем горутину

// Считываем данные из канала
for step := range progress {
fmt.Printf("Получен сигнал: шаг %d завершен\n", step)
}
fmt.Println("Все шаги выполнены!")
}


🟠Тайм-ауты и проверка работы через `select`
Если важно знать, работает ли горутина, но при этом нужно ограничить ожидание, используется оператор select с тайм-аутом.
func worker(status chan string) {
time.Sleep(2 * time.Second) // Имитация работы
status <- "Горутина завершена"
}

func main() {
status := make(chan string)

go worker(status)

select {
case msg := <-status:
fmt.Println(msg)
case <-time.After(1 * time.Second): // Тайм-аут 1 секунда
fmt.Println("Горутина работает слишком долго")
}
}


🟠Закрытие канала как индикатор завершения
Закрытие канала может служить сигналом того, что горутина завершила свою работу.
func worker(done chan struct{}) {
fmt.Println("Горутина работает...")
time.Sleep(2 * time.Second)
fmt.Println("Горутина завершена!")
close(done) // Закрываем канал
}

func main() {
done := make(chan struct{})

go worker(done)

// Проверяем, когда канал закроется
<-done
fmt.Println("Основной поток: горутина завершила работу")
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍5
🤔 В чём сложность удаления из начала внутри динамического массива (слайса) ?

Удаление из начала слайса требует сдвига всех оставшихся элементов на один шаг влево. Это операция линейной сложности — O(n), где n — количество элементов после удалённого.
В отличие от удаления с конца, которое обычно O(1), начало требует перераспределения памяти или сдвига указателей.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔5
🤔 Безопасен ли map?

Нет, карты (maps) в Go не являются потокобезопасными по умолчанию. Использование карты в нескольких горутинах без должной синхронизации может привести к состояниям гонки, некорректным данным и паникам. Давайте рассмотрим более детально, почему это так и как можно обеспечить потокобезопасность при работе с картами в многопоточной среде.

🚩Почему карты в Go не потокобезопасны

Карты в Go разработаны для обеспечения высокой производительности при использовании в однопоточных сценариях. Если несколько горутин одновременно пытаются читать и изменять карту, возникает конкуренция за доступ к данным, что может привести к следующим проблемам:

🟠Состояния гонки
Одновременный доступ к карте из нескольких горутин может привести к состояниям гонки, когда порядок выполнения операций непредсказуем.
🟠Паники
Одновременное изменение структуры карты, например добавление или удаление элементов, может вызвать панику в программе.

🚩Подходы к обеспечению потокобезопасности

🟠Мьютексы (Mutex)
Самый распространенный способ синхронизации доступа к карте — использование sync.Mutex. Мьютексы позволяют заблокировать доступ к карте на время чтения или записи.
package main

import (
"fmt"
"sync"
)

func main() {
var mu sync.Mutex
m := make(map[string]int)
var wg sync.WaitGroup

write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}

read := func(key string) int {
mu.Lock()
defer mu.Unlock()
return m[key]
}

wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}


🟠RWMutex
Если в вашей программе чаще происходят операции чтения, чем записи, можно использовать sync.RWMutex, который позволяет нескольким горутинам читать данные одновременно, но обеспечивает эксклюзивный доступ для записи.
package main

import (
"fmt"
"sync"
)

func main() {
var mu sync.RWMutex
m := make(map[string]int)
var wg sync.WaitGroup

write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}

read := func(key string) int {
mu.RLock()
defer mu.RUnlock()
return m[key]
}

wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}


🟠sync.Map
Go предоставляет специальную структуру sync.Map, которая изначально создана для безопасного использования в многопоточной среде. Она автоматически обеспечивает синхронизацию операций.
package main

import (
"fmt"
"sync"
)

func main() {
var m sync.Map
var wg sync.WaitGroup

wg.Add(2)
go func() {
defer wg.Done()
m.Store("key1", 42)
}()
go func() {
defer wg.Done()
value, _ := m.Load("key1")
fmt.Println(value)
}()
wg.Wait()
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Где потокобезопасность map безопасна?

Map безопасен только в однопоточных сценариях или при использовании внешней синхронизации, например, с помощью мьютекса.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Как работает append в слайсе ?

Функция 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⃣Начальный слайс
Создаем слайс с тремя элементами [1, 2, 3].
slice := []int{1, 2, 3}   


2⃣Добавление одного элемента
Добавляем элемент 4 к слайсу. Теперь слайс содержит [1, 2, 3, 4].
slice = append(slice, 4)   


3⃣Добавление нескольких элементов
Добавляем элементы 5, 6, и 7. Теперь слайс содержит [1, 2, 3, 4, 5, 6, 7].
slice = append(slice, 5, 6, 7)   


4⃣Вывод слайса
Выводим слайс, который содержит [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
👍3
🤔 Что такое goto?

goto — это инструкция, позволяющая выполнить безусловный переход к метке внутри функции. Она редко используется, так как может ухудшать читаемость и структуру кода, но иногда бывает полезна для упрощения выхода из вложенных циклов.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊7👍1
🤔 Что такое триггер?

Триггер — это специальная процедура в СУБД, которая автоматически выполняется при определённом событии (например, INSERT, UPDATE, DELETE) в таблице.

🚩Как работают триггеры?

Когда выполняется определённое действие с таблицей, триггер срабатывает автоматически и выполняет заданную логику. Это полезно для:
- Автоматической проверки данных.
- Поддержания целостности информации.
- Логирования изменений.

🚩Пример триггера в PostgreSQL

Допустим, у нас есть таблица orders, и мы хотим автоматически сохранять историю изменений заказов в таблицу orders_log.
CREATE TABLE orders_log (
id SERIAL PRIMARY KEY,
order_id INT,
old_status TEXT,
new_status TEXT,
changed_at TIMESTAMP DEFAULT now()
);

CREATE OR REPLACE FUNCTION log_order_update()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO orders_log (order_id, old_status, new_status)
VALUES (OLD.id, OLD.status, NEW.status);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER order_status_change
AFTER UPDATE ON orders
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION log_order_update();


🚩Разновидности триггеров

🟠До выполнения операции (`BEFORE`)
Используется для проверки или модификации данных перед изменением.

🟠После выполнения операции (`AFTER`)
Чаще всего используется для логирования или дополнительных действий.

🟠INSTEAD OF (для представлений)
Позволяет заменить выполнение операции (INSERT, UPDATE, DELETE).

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Какие ключи могут быть в Map?

Ключи должны быть сравнимыми типами, которые можно проверять на равенство.
1. Допустимые типы:
- Примитивы: int, float, string, bool.
- Указатели.
- Структуры, если все их поля имеют сравнимые типы.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Forwarded from easyoffer
Официальный релиз easyoffer 2.0 состоится уже в течение нескольких дней.

Напоминаю, что в честь релиза запускаем акцию.

Первые 500 покупателей получат:

🚀 Скидку 50% на PRO тариф на 1 год
🎁 Подарок ценностью 5000₽ для тех, кто подписан на этот канал

🔔 Подпишитесь на этот канал: https://t.me/+b2fZN17A9OQ3ZmJi
В нем мы опубликуем сообщение о релизе в первую очередь
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое тип rune Зачем их использовать?

Тип rune представляет собой alias для типа int32, предназначенного для хранения Unicode кодовых точек.

🚩Зачем он нужен?

🟠Работа с символами Unicode
Строки (string) являются последовательностями байтов, а не символов. Это означает, что один символ может занимать больше одного байта, особенно если это символ из расширенного набора Unicode.
Тип используется для работы с символами, представляемыми одной кодовой точкой Unicode. Это упрощает манипуляции с символами, так как каждая rune — это отдельный символ, независимо от его длины в байтах.

🟠Повышение читабельности кода
Использование типа rune делает код более понятным и само-документируемым. Когда в коде виден тип rune, это сразу указывает на то, что переменная предназначена для хранения одного символа, а не целого числа.

🚩Как его использовать ?

Создание и инициализация
      var r rune = '世'
fmt.Println(r) // Output: 19990


Итерация по строке
      s := "Привет, 世界"
for _, r := range s {
fmt.Printf("%c ", r)
}
// Output: П р и в е т , 世 界


Преобразование между string ито такое
      s := "Go"
runes := []rune(s)
fmt.Println(runes) // Output: [71 111]

s2 := string(runes)
fmt.Println(s2) // Output: Go


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
🤔 Что такое интерфейсы?

Интерфейсы в Go — это набор методов, которые должны быть реализованы типом для соответствия этому интерфейсу. Типы в Go не требуют явного указания реализации интерфейса; достаточно реализовать все его методы. Интерфейсы позволяют создавать гибкие и расширяемые программы, поддерживающие полиморфизм. Интерфейсы широко используются для создания общих алгоритмов и структур данных.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Что такое массив (array)?

Массив (array) — это структура данных, которая представляет собой фиксированную последовательность элементов одного типа. Все элементы массива размещены в памяти последовательно и имеют одинаковый тип. Используются для хранения коллекций данных, где количество элементов заранее известно и фиксировано.

🚩Основные характеристики

🟠Фиксированный размер
Размер массива задается при его объявлении и не может изменяться во время выполнения программы.
🟠Тип элементов
Все элементы массива имеют один и тот же тип.
🟠Непрерывное размещение в памяти
Элементы массива хранятся последовательно в памяти, что обеспечивает быстрый доступ к любому элементу по индексу.

🚩Объявление и инициализация массивов

Массивы объявляются с указанием типа элементов и фиксированного размера:
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]


🟠Сравнение массивов
С помощью оператора ==, если они имеют одинаковую длину и тип элементов:
arr1 := [3]int{1, 2, 3}
arr2 := [3]int{1, 2, 3}
arr3 := [3]int{4, 5, 6}

fmt.Println(arr1 == arr2) // true
fmt.Println(arr1 == arr3) // false


Пример
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