Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Хэш таблицы в Go: детали реализации

Хэш таблицы в Go: детали реализации

Iskander (Alex) Sharipov

February 16, 2019
Tweet

More Decks by Iskander (Alex) Sharipov

Other Decks in Programming

Transcript

  1. Хэш
    Хэш таблицы
    таблицы в
    в Go.
    Go. Детали
    Детали
    Хэш таблицы в Go. Детали
    реализации
    реализации
    реализации
    Колистратова
    Колистратова Дарья
    Дарья
    Колистратова Дарья
    Software Engineer, RetailNext
    Software Engineer, RetailNext
    Software Engineer, RetailNext

    View Slide

  2. Что
    Что такое
    такое хэш
    хэш-
    -таблица
    таблица?
    ?
    Что такое хэш-таблица?
    Необходимые
    Необходимые атрибуты
    атрибуты:
    :
    Необходимые атрибуты:
    Функция
    Функция маппинга
    маппинга
    Функция маппинга
    map(key)
    map(key) →
    → value
    value
    map(key) → value
    Вставка
    Вставка
    Вставка
    insert(map, key, value)
    insert(map, key, value)
    insert(map, key, value)
    Удаление
    Удаление
    Удаление
    delete(map, key)
    delete(map, key)
    delete(map, key)
    Поиск
    Поиск
    Поиск
    lookup(key)
    lookup(key) →
    → value
    value
    lookup(key) → value
    2
    2
    2

    View Slide

  3. Хэш
    Хэш-
    -таблица
    таблица в
    в языке
    языке go
    go
    Хэш-таблица в языке go
    Создание
    Создание
    Создание
    m := make(map[key_type]value_type)
    m := make(map[key_type]value_type)
    m := make(map[key_type]value_type)
    m := new(map[key_type]value_type)
    m := new(map[key_type]value_type)
    m := new(map[key_type]value_type)
    var m map[key_type]value_type
    var m map[key_type]value_type
    var m map[key_type]value_type
    m := map[key_type]value_type{key1: val1, key2: val2}
    m := map[key_type]value_type{key1: val1, key2: val2}
    m := map[key_type]value_type{key1: val1, key2: val2}
    Вставка
    Вставка
    Вставка
    m[key] = value
    m[key] = value
    m[key] = value
    Удаление
    Удаление
    Удаление
    delete(m, key)
    delete(m, key)
    delete(m, key)
    Поиск
    Поиск
    Поиск
    value = m[key]
    value = m[key]
    value = m[key]
    value, ok = m[key]
    value, ok = m[key]
    value, ok = m[key]
    3
    3
    3

    View Slide

  4. Обход
    Обход таблицы
    таблицы
    Обход таблицы
    Причина
    Причина:
    :
    Причина:
    // mapiterinit initializes the hiter struct used for ranging over maps.
    // mapiterinit initializes the hiter struct used for ranging over maps.
    // mapiterinit initializes the hiter struct used for ranging over maps.
    func mapiterinit(t *maptype, h *hmap, it *hiter) {...
    func mapiterinit(t *maptype, h *hmap, it *hiter) {...
    func mapiterinit(t *maptype, h *hmap, it *hiter) {...
    // decide where to start
    // decide where to start
    // decide where to start
    r := uintptr(fastrand())
    r := uintptr(fastrand())
    r := uintptr(fastrand())
    ...
    ...
    ...
    it.startBucket = r & bucketMask(h.B)...}
    it.startBucket = r & bucketMask(h.B)...}
    it.startBucket = r & bucketMask(h.B)...}
    package main
    package main
    package main
    import "fmt"
    import "fmt"
    import "fmt"
    func main() {
    func main() {
    func main() {
    m := map[int]bool{}
    m := map[int]bool{}
    m := map[int]bool{}
    for i := 0; i < 50; i++ {
    for i := 0; i < 50; i++ {
    for i := 0; i < 50; i++ {
    m[i] = ((i % 2) == 0)
    m[i] = ((i % 2) == 0)
    m[i] = ((i % 2) == 0)
    }
    }
    }
    for k, v := range m {
    for k, v := range m {
    for k, v := range m {
    fmt.Printf("key: %d, value: %t\n", k, v)
    fmt.Printf("key: %d, value: %t\n", k, v)
    fmt.Printf("key: %d, value: %t\n", k, v)
    }
    }
    }
    }
    }
    } Run
    4
    4
    4

    View Slide

  5. Поиск
    Поиск в
    в таблице
    таблице
    Поиск в таблице
    package main
    package main
    package main
    import (
    import (
    import (
    "fmt"
    "fmt"
    "fmt"
    )
    )
    )
    func main() {
    func main() {
    func main() {
    m := map[int]int{0: 0, 1: 10}
    m := map[int]int{0: 0, 1: 10}
    m := map[int]int{0: 0, 1: 10}
    fmt.Println(m, m[0], m[1], m[2])
    fmt.Println(m, m[0], m[1], m[2])
    fmt.Println(m, m[0], m[1], m[2])
    }
    }
    } Run
    5
    5
    5

    View Slide

  6. Поиск
    Поиск в
    в таблице
    таблице
    Поиск в таблице
    "An attempt to fetch a map value with a key that is not present in the map will return the
    "An attempt to fetch a map value with a key that is not present in the map will return the
    "An attempt to fetch a map value with a key that is not present in the map will return the
    zero value for the type of the entries in the map.
    zero value for the type of the entries in the map.
    zero value for the type of the entries in the map.
    Sometimes you need to distinguish a missing entry from a zero value. You can discriminate
    Sometimes you need to distinguish a missing entry from a zero value. You can discriminate
    Sometimes you need to distinguish a missing entry from a zero value. You can discriminate
    with a form of multiple assignment." -
    with a form of multiple assignment." - спецификация
    спецификация Go.
    Go.
    with a form of multiple assignment." - спецификация Go.
    package main
    package main
    package main
    import (
    import (
    import (
    "fmt"
    "fmt"
    "fmt"
    )
    )
    )
    func main() {
    func main() {
    func main() {
    m := map[int]int{0: 0, 1: 10}
    m := map[int]int{0: 0, 1: 10}
    m := map[int]int{0: 0, 1: 10}
    m2, ok := m[2]
    m2, ok := m[2]
    m2, ok := m[2]
    if !ok {
    if !ok {
    if !ok {
    // somehow process this case
    // somehow process this case
    // somehow process this case
    m2 = 20
    m2 = 20
    m2 = 20
    }
    }
    }
    fmt.Println(m, m[0], m[1], m2)
    fmt.Println(m, m[0], m[1], m2)
    fmt.Println(m, m[0], m[1], m2)
    }
    }
    } Run
    6
    6
    6

    View Slide

  7. Создание
    Создание таблицы
    таблицы
    Создание таблицы
    VS
    VS
    VS
    package main
    package main
    package main
    func main() {
    func main() {
    func main() {
    var m map[string]int
    var m map[string]int
    var m map[string]int
    for _, word := range []string{"hello", "world", "from", "the",
    for _, word := range []string{"hello", "world", "from", "the",
    for _, word := range []string{"hello", "world", "from", "the",
    "best", "language", "in", "the", "world"} {
    "best", "language", "in", "the", "world"} {
    "best", "language", "in", "the", "world"} {
    m[word]++
    m[word]++
    m[word]++
    println(word, m[word])
    println(word, m[word])
    println(word, m[word])
    }
    }
    }
    }
    }
    } Run
    package main
    package main
    package main
    func main() {
    func main() {
    func main() {
    m := make(map[string]int)
    m := make(map[string]int)
    m := make(map[string]int)
    for _, word := range []string{"hello", "world", "from", "the",
    for _, word := range []string{"hello", "world", "from", "the",
    for _, word := range []string{"hello", "world", "from", "the",
    "best", "language", "in", "the", "world"} {
    "best", "language", "in", "the", "world"} {
    "best", "language", "in", "the", "world"} {
    m[word]++
    m[word]++
    m[word]++
    println(word, m[word])
    println(word, m[word])
    println(word, m[word])
    }
    }
    }
    }
    }
    } Run
    7
    7
    7

    View Slide

  8. Как
    Как передается
    передается map
    map в
    в функцию
    функцию?
    ?
    Как передается map в функцию?
    VS
    VS
    VS
    package main
    package main
    package main
    func foo(n int) { n = 10 }
    func foo(n int) { n = 10 }
    func foo(n int) { n = 10 }
    func main() {
    func main() {
    func main() {
    n := 15
    n := 15
    n := 15
    println("n before foo =", n)
    println("n before foo =", n)
    println("n before foo =", n)
    foo(n)
    foo(n)
    foo(n)
    println("n after foo =", n)
    println("n after foo =", n)
    println("n after foo =", n)
    }
    }
    } Run
    package main
    package main
    package main
    func foo(m map[int]int) { m[10] = 10 }
    func foo(m map[int]int) { m[10] = 10 }
    func foo(m map[int]int) { m[10] = 10 }
    func main() {
    func main() {
    func main() {
    m := make(map[int]int)
    m := make(map[int]int)
    m := make(map[int]int)
    m[10] = 15
    m[10] = 15
    m[10] = 15
    println("m[10] before foo =", m[10])
    println("m[10] before foo =", m[10])
    println("m[10] before foo =", m[10])
    foo(m)
    foo(m)
    foo(m)
    println("m[10] after foo =", m[10])
    println("m[10] after foo =", m[10])
    println("m[10] after foo =", m[10])
    }
    }
    } Run
    8
    8
    8

    View Slide

  9. Map
    Map передается
    передается ссылке
    ссылке?
    ?
    Map передается ссылке?
    --
    -- Нет
    Нет.
    .
    -- Нет.
    *
    * в
    в go
    go не
    не бывает
    бывает ссылок
    ссылок.
    . Невозможно
    Невозможно создать
    создать 2
    2 переменные
    переменные с
    с одним
    одним адресом
    адресом,
    ,
    * в go не бывает ссылок. Невозможно создать 2 переменные с одним адресом,
    зато
    зато можно
    можно создать
    создать 2
    2 переменные
    переменные,
    , указывающие
    указывающие на
    на один
    один адрес
    адрес (
    (но
    но это
    это уже
    уже не
    не ссылка
    ссылка,
    , а
    а указатель
    указатель)
    )
    зато можно создать 2 переменные, указывающие на один адрес (но это уже не ссылка, а указатель)
    package main
    package main
    package main
    import "fmt"
    import "fmt"
    import "fmt"
    func fn(m map[int]int) {
    func fn(m map[int]int) {
    func fn(m map[int]int) {
    m = make(map[int]int)
    m = make(map[int]int)
    m = make(map[int]int)
    fmt.Println("m == nil in fn?:", m == nil)
    fmt.Println("m == nil in fn?:", m == nil)
    fmt.Println("m == nil in fn?:", m == nil)
    }
    }
    }
    func main() {
    func main() {
    func main() {
    var m map[int]int
    var m map[int]int
    var m map[int]int
    fn(m)
    fn(m)
    fn(m)
    fmt.Println("m == nil in main?:", m == nil)
    fmt.Println("m == nil in main?:", m == nil)
    fmt.Println("m == nil in main?:", m == nil)
    }
    }
    } Run
    9
    9
    9

    View Slide

  10. Тип
    Тип map -
    map - что
    что же
    же это
    это?
    ?
    Тип map - что же это?
    Исходный
    Исходный код
    код из
    из пакета
    пакета runtime:
    runtime:
    Исходный код из пакета runtime:
    // A header for a Go map.
    // A header for a Go map.
    // A header for a Go map.
    type hmap struct {
    type hmap struct {
    type hmap struct {
    // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
    // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
    // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
    // Make sure this stays in sync with the compiler's definition.
    // Make sure this stays in sync with the compiler's definition.
    // Make sure this stays in sync with the compiler's definition.
    count int // # live cells == size of map. Must be first (used by len() builtin)
    count int // # live cells == size of map. Must be first (used by len() builtin)
    count int // # live cells == size of map. Must be first (used by len() builtin)
    flags uint8
    flags uint8
    flags uint8
    B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
    B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
    B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
    noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
    noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
    noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
    hash0 uint32 // hash seed
    hash0 uint32 // hash seed
    hash0 uint32 // hash seed
    buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
    buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
    buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
    oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
    oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
    oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
    nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacu
    nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacu
    nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacu
    extra *mapextra // optional fields
    extra *mapextra // optional fields
    extra *mapextra // optional fields
    }
    }
    }
    10
    10
    10

    View Slide

  11. Реализация
    Реализация
    Реализация
    11
    11
    11

    View Slide

  12. Как
    Как растет
    растет map?
    map?
    Как растет map?
    map source: // Maximum average load of a bucket that triggers growth is 6.5.
    map source: // Maximum average load of a bucket that triggers growth is 6.5.
    map source: // Maximum average load of a bucket that triggers growth is 6.5.
    Если
    Если в
    в каждом
    каждом "
    "ведре
    ведре"
    " более
    более 6,5
    6,5 элементов
    элементов,
    , происходит
    происходит увеличение
    увеличение массива
    массива.
    .
    Если в каждом "ведре" более 6,5 элементов, происходит увеличение массива.
    Выделяется
    Выделяется в
    в 2
    2 раза
    раза больше
    больше массив
    массив.
    .
    Выделяется в 2 раза больше массив.
    Старые
    Старые данные
    данные копируются
    копируются в
    в него
    него.
    .
    Старые данные копируются в него.
    -
    - это
    это происходит
    происходит не
    не за
    за один
    один подход
    подход,
    , а
    а понемногу
    понемногу каждые
    каждые вставку
    вставку и
    и удаление
    удаление,
    ,
    - это происходит не за один подход, а понемногу каждые вставку и удаление,
    поэтому
    поэтому операции
    операции будут
    будут чуть
    чуть медленнее
    медленнее в
    в процессе
    процессе эвакуации
    эвакуации данных
    данных.
    .
    поэтому операции будут чуть медленнее в процессе эвакуации данных.
    Начинают
    Начинают использоваться
    использоваться новые
    новые.
    .
    Начинают использоваться новые.
    12
    12
    12

    View Slide

  13. Взятие
    Взятие адреса
    адреса элемента
    элемента map.
    map.
    Взятие адреса элемента map.
    package main
    package main
    package main
    import (
    import (
    import (
    "fmt"
    "fmt"
    "fmt"
    )
    )
    )
    func main() {
    func main() {
    func main() {
    m := make(map[int]int)
    m := make(map[int]int)
    m := make(map[int]int)
    m[1] = 10
    m[1] = 10
    m[1] = 10
    a := &m[1]
    a := &m[1]
    a := &m[1]
    fmt.Println(m[1], *a)
    fmt.Println(m[1], *a)
    fmt.Println(m[1], *a)
    }
    }
    } Run
    13
    13
    13

    View Slide

  14. Как
    Как реализована
    реализована map
    map без
    без generic
    genericов
    ов?
    ?
    Как реализована map без genericов?
    Используется
    Используется interface{}?
    interface{}?
    Используется interface{}?
    -
    - Нет
    Нет.
    .
    - Нет.
    Может
    Может быть
    быть,
    , кодогенераця
    кодогенераця?
    ?
    Может быть, кодогенераця?
    -
    - Тоже
    Тоже нет
    нет.
    .
    - Тоже нет.
    14
    14
    14

    View Slide

  15. Как
    Как реализована
    реализована map
    map без
    без generic
    genericов
    ов?
    ?
    Как реализована map без genericов?
    Замена
    Замена во
    во время
    время компиляции
    компиляции.
    .
    Замена во время компиляции.
    v := m["k"]
    v := m["k"] →
    → func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
    func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
    v := m["k"] → func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
    v, ok := m["k"]
    v, ok := m["k"] →
    → func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
    func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
    v, ok := m["k"] → func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
    m["k"] = 9001
    m["k"] = 9001 →
    → func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
    func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
    m["k"] = 9001 → func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
    delete(m, "k")
    delete(m, "k") →
    → func mapdelete(t *maptype, h *hmap, key unsafe.Pointer)
    func mapdelete(t *maptype, h *hmap, key unsafe.Pointer)
    delete(m, "k") → func mapdelete(t *maptype, h *hmap, key unsafe.Pointer)
    Все
    Все операции
    операции используют
    используют unsafe.Pointers
    unsafe.Pointers на
    на значения
    значения общего
    общего типа
    типа.
    .
    Все операции используют unsafe.Pointers на значения общего типа.
    Информация
    Информация о
    о типе
    типе каждого
    каждого значения
    значения описывается
    описывается дескриптором
    дескриптором типа
    типа.
    .
    Информация о типе каждого значения описывается дескриптором типа.
    Для
    Для дескриптора
    дескриптора типа
    типа определены
    определены операции
    операции ==, hash,
    ==, hash, размеры
    размеры и
    и т
    т.

    д.
    .
    Для дескриптора типа определены операции ==, hash, размеры и т.д.
    type mapType struct {
    type mapType struct {
    type mapType struct {
    key *_type
    key *_type
    key *_type
    elem *_type ...}
    elem *_type ...}
    elem *_type ...}
    type _type struct {
    type _type struct {
    type _type struct {
    size uintptr
    size uintptr
    size uintptr
    alg *typeAlg ...}
    alg *typeAlg ...}
    alg *typeAlg ...}
    type typeAlg struct {
    type typeAlg struct {
    type typeAlg struct {
    hash func(unsafe.Pointer, uintptr) uintptr
    hash func(unsafe.Pointer, uintptr) uintptr
    hash func(unsafe.Pointer, uintptr) uintptr
    equal func(unsafe.Pointer, unsafe.Pointer) bool }
    equal func(unsafe.Pointer, unsafe.Pointer) bool }
    equal func(unsafe.Pointer, unsafe.Pointer) bool }
    15
    15
    15

    View Slide

  16. Пример
    Пример
    Пример
    Поиск
    Поиск трансформируется
    трансформируется во
    во что
    что-
    -то
    то подобное
    подобное:
    :
    Поиск трансформируется во что-то подобное:
    v = m[k] ->
    v = m[k] ->
    v = m[k] ->
    {
    {
    {
    kPointer := unsafe.Pointer(&k)
    kPointer := unsafe.Pointer(&k)
    kPointer := unsafe.Pointer(&k)
    vPointer := mapaccess1(typeOf(m), m, kPointer)
    vPointer := mapaccess1(typeOf(m), m, kPointer)
    vPointer := mapaccess1(typeOf(m), m, kPointer)
    v = *(*typeOfvalue)vPointer
    v = *(*typeOfvalue)vPointer
    v = *(*typeOfvalue)vPointer
    }
    }
    }
    16
    16
    16

    View Slide

  17. Пример
    Пример
    Пример
    // lookup looks up a key in a map and returns a pointer to the associated value.
    // lookup looks up a key in a map and returns a pointer to the associated value.
    // lookup looks up a key in a map and returns a pointer to the associated value.
    // t = type of the map
    // t = type of the map
    // t = type of the map
    // m = map
    // m = map
    // m = map
    // key = pointer to key
    // key = pointer to key
    // key = pointer to key
    func lookup(t *mapType, m *mapHeader, key unsafe.Pointer) unsafe.Pointer {
    func lookup(t *mapType, m *mapHeader, key unsafe.Pointer) unsafe.Pointer {
    func lookup(t *mapType, m *mapHeader, key unsafe.Pointer) unsafe.Pointer {
    if m == nil || m.count == 0 {
    if m == nil || m.count == 0 {
    if m == nil || m.count == 0 {
    return zero
    return zero
    return zero
    }
    }
    }
    hash := t.key.hash(key, m.seed) // hash := hashfn(key)
    hash := t.key.hash(key, m.seed) // hash := hashfn(key)
    hash := t.key.hash(key, m.seed) // hash := hashfn(key)
    bucket := hash & (1<bucket := hash & (1<bucket := hash & (1<extra := byte(hash >> 56) // extra := top 8 bits of hash
    extra := byte(hash >> 56) // extra := top 8 bits of hash
    extra := byte(hash >> 56) // extra := top 8 bits of hash
    b := (*bucket)(add(m.buckets, bucket*t.bucketsize)) // b := &m.buckets[bucket]
    b := (*bucket)(add(m.buckets, bucket*t.bucketsize)) // b := &m.buckets[bucket]
    b := (*bucket)(add(m.buckets, bucket*t.bucketsize)) // b := &m.buckets[bucket]
    -
    -
    -
    by Keith Randall
    by Keith Randall
    by Keith Randall
    17
    17
    17

    View Slide

  18. Пример
    Пример
    Пример
    for {
    for {
    for {
    for i := 0; i < 8; i++ {
    for i := 0; i < 8; i++ {
    for i := 0; i < 8; i++ {
    if b.extra[i] != extra { // check 8 extra hash bits
    if b.extra[i] != extra { // check 8 extra hash bits
    if b.extra[i] != extra { // check 8 extra hash bits
    continue
    continue
    continue
    }
    }
    }
    k := add(b, dataOffset+i*t.key.size) // pointer to ki in bucket
    k := add(b, dataOffset+i*t.key.size) // pointer to ki in bucket
    k := add(b, dataOffset+i*t.key.size) // pointer to ki in bucket
    if t.key.equal(key, k) {
    if t.key.equal(key, k) {
    if t.key.equal(key, k) {
    // return pointer to vi
    // return pointer to vi
    // return pointer to vi
    return add(b, dataOffset+8*t.key.size+i*t.value.size)
    return add(b, dataOffset+8*t.key.size+i*t.value.size)
    return add(b, dataOffset+8*t.key.size+i*t.value.size)
    }
    }
    }
    }
    }
    }
    b = b.overflow
    b = b.overflow
    b = b.overflow
    if b == nil {
    if b == nil {
    if b == nil {
    return zero
    return zero
    return zero
    }
    }
    }
    }
    }
    }
    -
    -
    -
    by Keith Randall
    by Keith Randall
    by Keith Randall
    18
    18
    18

    View Slide

  19. Заключение
    Заключение
    Заключение
    Используйте
    Используйте мапы
    мапы!
    !
    Используйте мапы!
    И
    И знайте
    знайте как
    как и
    и почему
    почему они
    они работают
    работают.
    .
    И знайте как и почему они работают.
    19
    19
    19

    View Slide

  20. Вопросы
    Вопросы?
    ?
    Вопросы?
    20
    20
    20

    View Slide

  21. Ссылки
    Ссылки
    Ссылки
    "Go maps in action", Andrew Gerrand
    "Go maps in action", Andrew Gerrand
    "Go maps in action", Andrew Gerrand (https://blog.golang.org/go-maps-in-action)
    (https://blog.golang.org/go-maps-in-action)
    (https://blog.golang.org/go-maps-in-action)
    "How the go runtime implements maps e ciently", Dave Cheney
    "How the go runtime implements maps e ciently", Dave Cheney
    "How the go runtime implements maps e ciently", Dave Cheney (https://dave.cheney.net/2018/05/29/how-the-go-
    (https://dave.cheney.net/2018/05/29/how-the-go-
    (https://dave.cheney.net/2018/05/29/how-the-go-
    runtime-implements-maps-e ciently-without-generics#easy-footnote-1-3224)
    runtime-implements-maps-e ciently-without-generics#easy-footnote-1-3224)
    runtime-implements-maps-e ciently-without-generics#easy-footnote-1-3224)
    "Understanding type in go, William Kennedy
    "Understanding type in go, William Kennedy
    "Understanding type in go, William Kennedy (https://www.ardanlabs.com/blog/2013/07/understanding-type-in-go.html)
    (https://www.ardanlabs.com/blog/2013/07/understanding-type-in-go.html)
    (https://www.ardanlabs.com/blog/2013/07/understanding-type-in-go.html)
    "Inside the Map Implementation", Keith Randall
    "Inside the Map Implementation", Keith Randall
    "Inside the Map Implementation", Keith Randall (https://www.youtube.com/watch?v=Tl7mi9QmLns&feature=youtu.be)
    (https://www.youtube.com/watch?v=Tl7mi9QmLns&feature=youtu.be)
    (https://www.youtube.com/watch?v=Tl7mi9QmLns&feature=youtu.be)
    "map source code", Go Runtime
    "map source code", Go Runtime
    "map source code", Go Runtime (https://github.com/golang/go/blob/master/src/runtime/map.go)
    (https://github.com/golang/go/blob/master/src/runtime/map.go)
    (https://github.com/golang/go/blob/master/src/runtime/map.go)
    golang spec
    golang spec
    golang spec (https://golang.org/ref/spec)
    (https://golang.org/ref/spec)
    (https://golang.org/ref/spec)
    e ective go
    e ective go
    e ective go (https://golang.org/doc/e ective_go.html)
    (https://golang.org/doc/e ective_go.html)
    (https://golang.org/doc/e ective_go.html)
    картинки
    картинки с
    с гоферами
    гоферами
    картинки с гоферами (https://github.com/shalakhin/gophericons)
    (https://github.com/shalakhin/gophericons)
    (https://github.com/shalakhin/gophericons) 21
    21
    21

    View Slide

  22. Thank you
    Thank you
    Thank you
    Колистратова
    Колистратова Дарья
    Дарья
    Колистратова Дарья
    Software Engineer, RetailNext
    Software Engineer, RetailNext
    Software Engineer, RetailNext
    [email protected]
    [email protected]
    da[email protected] (mailto:[email protected])
    (mailto:[email protected])
    (mailto:[email protected])
    https://www.facebook.com/daria.kolistratova
    https://www.facebook.com/daria.kolistratova
    https://www.facebook.com/daria.kolistratova (https://www.facebook.com/daria.kolistratova)
    (https://www.facebook.com/daria.kolistratova)
    (https://www.facebook.com/daria.kolistratova)
    https://vk.com/dakolistratova
    https://vk.com/dakolistratova
    https://vk.com/dakolistratova (https://vk.com/dakolistratova)
    (https://vk.com/dakolistratova)
    (https://vk.com/dakolistratova)

    View Slide