Irbisa · Шпаргалка
Слайсы, мапы и строки
Заголовок слайса, алиасинг при append, внутренности map, руны и strings.Builder
Чем массив отличается от слайса в Go и что хранит заголовок слайса?
arr := [4]int{1, 2, 3, 4}cp := arr // array: full copycp[0] = 99fmt.Println(arr[0]) // 1 s := arr[1:3] // slice over arr: len 2, cap 3…Чем nil-слайс отличается от пустого слайса и что можно делать с nil-слайсом?
Чем
make([]T, n)отличается отmake([]T, 0, n)и что пойдёт не так, если делатьappendв первый?in := []string{"a", "b", "c"} // wrong: three zero Rows first, then the three real onesout := make([]Row, len(in))for _, v := range in { out = append(out, Row{Key: v})…Как сделать независимую копию слайса и почему
copyвmake([]T, 0, n)ничего не копирует?a := []int{1, 2, 3} b := a // header copy: same arrayb[0] = 99fmt.Println(a[0]) // 99…Что выведет этот цикл и как менять элементы слайса внутри цикла
range?type Item struct { Name string Count int} items := []Item{{"a", 1}, {"b", 2}}for _, it := range items { it.Count++}fmt.Println(items)Почему
len("Дмитрий")возвращает 14 и как считать, индексировать и перебирать символы строки в Go?name := "Дмитрий" fmt.Println(len(name)) // 14 (bytes)fmt.Println(utf8.RuneCountInString(name)) // 7 (runes)fmt.Println(name[0]) // 208 (one byte, not "Д")…Как проверить, есть ли ключ в мапе, и что будет при записи в мапу, которую не инициализировали?
orders := map[string]int{"ada": 0} fmt.Println(orders["grace"]) // 0 (missing key, no panic)n, ok := orders["ada"]fmt.Println(n, ok) // 0 true (a stored zero)…Почему порядок обхода мапы в Go случайный и как получить стабильный порядок?
m := map[string]int{"b": 2, "a": 1, "c": 3} for k, v := range m { // the order differs between runs fmt.Println(k, v)}…Как отсортировать слайс структур по одному полю и по двум полям?
type User struct { Name string Age int} users := []User{{"Bob", 30}, {"Alice", 30}, {"Eve", 25}}…Слайс передаётся в функцию по значению или по ссылке? Что выведет эта программа?
func add(s []int) { s[0] = 100 s = append(s, 4) s[1] = 200} func main() { a := make([]int, 3, 10) add(a) fmt.Println(a, len(a), a[:4])}Как
appendувеличивает слайс и когда он выделяет новый массив?var sink []int var s []intprev := -1for i := 0; i < 2000; i++ { s = append(s, i)…Из одного базового слайса делают два
append. Что выведет этот код и почему?base := make([]int, 2, 3) // [0 0], one free slotx := append(base, 1)y := append(base, 2)fmt.Println(x, y) z := append(x, 3) // x is already fullz[0] = 7fmt.Println(x[0], z[0])Что делает трёхиндексное выражение среза
s[low:high:max]и когда оно нужно?buf := []int{1, 2, 3, 4, 5} head := buf[:2] // len 2, cap 5head = append(head, 99) // overwrites buf[2]fmt.Println(buf) // [1 2 99 4 5]…Почему сборка строки через
s += partв цикле медленная и когда братьstrings.Builder,strings.Joinилиbytes.Buffer?// wrong: each += copies everything built so fars := ""for _, line := range lines { s += line + "\n"}…Безопасно ли удалять ключи из мапы или добавлять их во время обхода
range?Почему
m["a"].Count++не компилируется, еслиmимеет типmap[string]Item, и как обновить структуру, лежащую в мапе?type Item struct{ Count int } m := map[string]Item{"a": {Count: 1}}m["a"].Count++ // wrong: cannot assign to struct field m["a"].Count in map it := m["a"] // right: copy out, change, store back…Как устроена мапа в Go и что изменилось, когда Go 1.24 перешёл на Swiss tables?
Безопасна ли мапа в Go для конкурентного использования? Что будет при одновременной записи и как защитить общую мапу?
type Cache struct { mu sync.RWMutex m map[string]Entry} func NewCache() *Cache {…Что заменяют пакеты
slicesиmapsи какие функцииslicesменяют переданный слайс?ids := []int{3, 1, 3, 2}fmt.Println(slices.Contains(ids, 2), slices.Index(ids, 3)) // true 0 slices.Sort(ids) // in place: [1 2 3 3]ids = slices.Compact(ids) // [1 2 3]ids = slices.Insert(ids, 1, 10) // [1 10 2 3]…Найдите баг: после
removeExpiredчасть просроченных сессий остаётся в слайсе.type Session struct { ID string ExpiresAt time.Time} // removeExpired drops every session that has expired.func removeExpired(sessions []Session, now time.Time) []Session { for i := 0; i < len(sessions); i++ { if sessions[i].ExpiresAt.Before(now) { sessions = append(sessions[:i], sessions[i+1:]...) } } return sessions}Освобождает ли
s = s[:5]остаток большого слайса? Как маленький подслайс удерживает в памяти большой массив?var keep []byte keep = body[:64] // wrong: pins the whole 4 MB bodykeep = bytes.Clone(body[:64]) // right: copy what you keep clear(s[n:]) // slice of pointers: drop the stale references…Удаление элемента через
s = append(s[:i], s[i+1:]...)работает, но как же оно может давать утечку памяти и что делает иначеslices.Delete?// the old last pointer stays in the slot past len(sessions)sessions = append(sessions[:i], sessions[i+1:]...) // Go 1.22+: the same shift, the vacated slot zeroedsessions = slices.Delete(sessions, i, i+1)…Могут ли несколько горутин использовать один слайс или буфер
[]byteи как делать это безопасно?func process(buf []byte, workers int) { size := (len(buf) + workers - 1) / workers var wg sync.WaitGroup for lo := 0; lo < len(buf); lo += size { hi := min(lo+size, len(buf)) wg.Add(1)…Найдите баг:
Renameотрабатывает без ошибок, ноListу части пользователей по-прежнему показывает старое имя.type Registry struct { users []User // keeps insertion order for List byID map[int]*User // fast lookup by ID} func (r *Registry) Add(u User) { r.users = append(r.users, u) r.byID[u.ID] = &r.users[len(r.users)-1]} func (r *Registry) Rename(id int, name string) { r.byID[id].Name = name} func (r *Registry) List() []User { return r.users }