Исходники и презентации
This commit is contained in:
32
lessons/maps/big_map/main.go
Normal file
32
lessons/maps/big_map/main.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func printAllocs() {
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
fmt.Printf("%d MB\n", m.Alloc/1024/1024)
|
||||
}
|
||||
|
||||
func main() {
|
||||
printAllocs()
|
||||
data := make(map[int][128]byte) // try to use 129
|
||||
printAllocs()
|
||||
|
||||
for i := 0; i < 1_000_000; i++ {
|
||||
data[i] = [128]byte{}
|
||||
}
|
||||
|
||||
printAllocs()
|
||||
|
||||
for i := 0; i < 1_000_000; i++ {
|
||||
delete(data, i)
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
printAllocs()
|
||||
runtime.KeepAlive(data)
|
||||
}
|
||||
21
lessons/maps/bucket_structure/main.go
Normal file
21
lessons/maps/bucket_structure/main.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type bucketV1 struct {
|
||||
key int8
|
||||
value int64
|
||||
}
|
||||
|
||||
type bucketV2 struct {
|
||||
keys [8]int8
|
||||
values [8]int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("bucketsV1:", unsafe.Sizeof([8]bucketV1{}))
|
||||
fmt.Println("bucketsV2:", unsafe.Sizeof(bucketV2{}))
|
||||
}
|
||||
11
lessons/maps/comparable_keys/main.go
Normal file
11
lessons/maps/comparable_keys/main.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
data := map[interface{}]int{
|
||||
"a": 1,
|
||||
2: 2,
|
||||
}
|
||||
|
||||
data[[]int{}] = 3
|
||||
data[func() {}] = 4
|
||||
}
|
||||
74
lessons/maps/comparison/comparison_test.go
Normal file
74
lessons/maps/comparison/comparison_test.go
Normal file
@ -0,0 +1,74 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// go test -bench=. comparison_test.go
|
||||
|
||||
type client struct {
|
||||
operations map[int]int
|
||||
}
|
||||
|
||||
func (c *client) equal(other *client) bool {
|
||||
if c == other {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(c.operations) != len(other.operations) {
|
||||
return false
|
||||
}
|
||||
|
||||
for key, value := range c.operations {
|
||||
otherValue, found := other.operations[key]
|
||||
if !found || value != otherValue {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func BenchmarkWithEqualFunction(b *testing.B) {
|
||||
lhs := client{
|
||||
operations: map[int]int{1: 2, 2: 5, 3: 7, 4: 9, 5: 10, 6: 3, 7: 4},
|
||||
}
|
||||
|
||||
rhs := client{
|
||||
operations: map[int]int{1: 2, 2: 5, 3: 7, 4: 9, 5: 10, 6: 3, 7: 4},
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = lhs.equal(&rhs) // maps.Equal()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithReflect(b *testing.B) {
|
||||
lhs := client{
|
||||
operations: map[int]int{1: 2, 2: 5, 3: 7, 4: 9, 5: 10, 6: 3, 7: 4},
|
||||
}
|
||||
|
||||
rhs := client{
|
||||
operations: map[int]int{1: 2, 2: 5, 3: 7, 4: 9, 5: 10, 6: 3, 7: 4},
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = reflect.DeepEqual(lhs, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithStringFunction(b *testing.B) {
|
||||
lhs := client{
|
||||
operations: map[int]int{1: 2, 2: 5, 3: 7, 4: 9, 5: 10, 6: 3, 7: 4},
|
||||
}
|
||||
|
||||
rhs := client{
|
||||
operations: map[int]int{1: 2, 2: 5, 3: 7, 4: 9, 5: 10, 6: 3, 7: 4},
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = fmt.Sprint(lhs) == fmt.Sprint(rhs)
|
||||
}
|
||||
}
|
||||
17
lessons/maps/delete_during_iteration/main.go
Normal file
17
lessons/maps/delete_during_iteration/main.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
data := map[string]int{"foo": 0, "bar": 1, "baz": 2}
|
||||
for key := range data {
|
||||
if key == "foo" {
|
||||
delete(data, "bar")
|
||||
}
|
||||
if key == "bar" {
|
||||
delete(data, "foo")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(data)
|
||||
}
|
||||
6
lessons/maps/element_value_address/main.go
Normal file
6
lessons/maps/element_value_address/main.go
Normal file
@ -0,0 +1,6 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
data := map[int]int{0: 1}
|
||||
_ = &data[0]
|
||||
}
|
||||
21
lessons/maps/hash_function/main.go
Normal file
21
lessons/maps/hash_function/main.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/maphash"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var h1 maphash.Hash
|
||||
h1.WriteString("hello")
|
||||
fmt.Println(h1.Sum64(), h1.Seed()) // random hash seed
|
||||
|
||||
var h2 maphash.Hash
|
||||
h2.WriteString("hello")
|
||||
fmt.Println(h2.Sum64(), h2.Seed()) // random hash seed
|
||||
|
||||
var h3 maphash.Hash
|
||||
h3.SetSeed(h2.Seed())
|
||||
h3.WriteString("hello")
|
||||
fmt.Println(h3.Sum64(), h3.Seed()) // hash seed from h2
|
||||
}
|
||||
16
lessons/maps/iteration_order/main.go
Normal file
16
lessons/maps/iteration_order/main.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
data := map[int]struct{}{
|
||||
1: {}, 2: {}, 3: {}, 4: {}, 5: {},
|
||||
}
|
||||
|
||||
for key := range data {
|
||||
fmt.Print(key, " ")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(data)
|
||||
}
|
||||
22
lessons/maps/map_clearing/main.go
Normal file
22
lessons/maps/map_clearing/main.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
// remove all elements
|
||||
first := map[int]int{1: 1, 2: 2, 3: 3}
|
||||
first = nil
|
||||
fmt.Println(first, " : ", len(first))
|
||||
|
||||
// keep allocated memory
|
||||
second := map[int]int{1: 1, 2: 2, 3: 3}
|
||||
for key := range second {
|
||||
delete(second, key)
|
||||
}
|
||||
fmt.Println(second, " : ", len(second))
|
||||
|
||||
// keep allocated memory
|
||||
third := map[int]int{1: 1, 2: 2, 3: 3}
|
||||
clear(third)
|
||||
fmt.Println(third, " : ", len(third))
|
||||
}
|
||||
11
lessons/maps/map_empty_assign/main.go
Normal file
11
lessons/maps/map_empty_assign/main.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
m := make(map[string]int, 3)
|
||||
x := len(m)
|
||||
|
||||
m["Go"] = m["Go"]
|
||||
|
||||
y := len(m)
|
||||
println(x, y)
|
||||
}
|
||||
46
lessons/maps/map_internals/main.go
Normal file
46
lessons/maps/map_internals/main.go
Normal file
@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type eface struct {
|
||||
typ unsafe.Pointer
|
||||
data unsafe.Pointer
|
||||
}
|
||||
|
||||
type hmap struct {
|
||||
count int
|
||||
flags uint8
|
||||
B uint8
|
||||
noverflow uint16
|
||||
hash0 uint32
|
||||
|
||||
buckets unsafe.Pointer
|
||||
oldbuckets unsafe.Pointer
|
||||
nevacuate uintptr
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := make(map[int]int)
|
||||
iface := any(data)
|
||||
|
||||
ifacePtr := unsafe.Pointer(&iface)
|
||||
emptyIfacePtr := (*eface)(ifacePtr)
|
||||
|
||||
hm := (*hmap)(emptyIfacePtr.data)
|
||||
fmt.Println("count:", hm.count, "buckets:", 1<<hm.B)
|
||||
|
||||
for i := 0; i < 500; i++ {
|
||||
data[i] = i * 2
|
||||
}
|
||||
|
||||
fmt.Println("count:", hm.count, "buckets:", 1<<hm.B)
|
||||
|
||||
for key := range data {
|
||||
delete(data, key)
|
||||
}
|
||||
|
||||
fmt.Println("count:", hm.count, "buckets:", 1<<hm.B)
|
||||
}
|
||||
36
lessons/maps/map_operations/main.go
Normal file
36
lessons/maps/map_operations/main.go
Normal file
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
func readFromNilMap() {
|
||||
var data map[int]int
|
||||
_ = data[100]
|
||||
}
|
||||
|
||||
func deleteFromNilMap() {
|
||||
var data map[int]int
|
||||
delete(data, 100)
|
||||
}
|
||||
|
||||
func writeToNilMap() {
|
||||
var data map[int]int
|
||||
data[100] = 100
|
||||
}
|
||||
|
||||
func rangeByNilMap() {
|
||||
var data map[int]int
|
||||
for range data {
|
||||
}
|
||||
}
|
||||
|
||||
func rewriteExistingKey() {
|
||||
data := make(map[int]int)
|
||||
data[100] = 500
|
||||
data[100] = 1000
|
||||
}
|
||||
|
||||
func deleteNonExistingKey() {
|
||||
data := make(map[int]int)
|
||||
delete(data, 100)
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
21
lessons/maps/map_performance/performance_test.go
Normal file
21
lessons/maps/map_performance/performance_test.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
// go test -bench=. performance_test.go
|
||||
|
||||
func BenchmarkWithSlice(b *testing.B) {
|
||||
slice := []int{1, 2, 3}
|
||||
for i := 0; i < b.N; i++ {
|
||||
value := slice[1]
|
||||
slice[1] = value
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithHashTable(b *testing.B) {
|
||||
table := map[int]int{0: 1, 1: 2, 2: 3}
|
||||
for i := 0; i < b.N; i++ {
|
||||
value := table[1]
|
||||
table[1] = value
|
||||
}
|
||||
}
|
||||
14
lessons/maps/map_with_float/main.go
Normal file
14
lessons/maps/map_with_float/main.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var value1 float32 = 0.3
|
||||
var value2 float32 = 0.6
|
||||
data := make(map[float32]struct{})
|
||||
data[value1+value2] = struct{}{}
|
||||
|
||||
var result float32 = 0.9
|
||||
_, found := data[result]
|
||||
fmt.Println(found)
|
||||
}
|
||||
14
lessons/maps/map_with_function_1/main.go
Normal file
14
lessons/maps/map_with_function_1/main.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func set(data map[int]int, key, value int) {
|
||||
data[key] = value
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := make(map[int]int)
|
||||
fmt.Println(data)
|
||||
set(data, 100, 500)
|
||||
fmt.Println(data)
|
||||
}
|
||||
14
lessons/maps/map_with_function_2/main.go
Normal file
14
lessons/maps/map_with_function_2/main.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func change(data map[int]int) {
|
||||
data = map[int]int{2: 20}
|
||||
}
|
||||
|
||||
func main() {
|
||||
data := map[int]int{1: 10}
|
||||
fmt.Println(data)
|
||||
change(data)
|
||||
fmt.Println(data)
|
||||
}
|
||||
12
lessons/maps/mapaccess/main.go
Normal file
12
lessons/maps/mapaccess/main.go
Normal file
@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
data := map[int]int{100: 10000}
|
||||
value := data[100]
|
||||
_ = value
|
||||
|
||||
// under hood
|
||||
// pk := unsafe.Pointer(&key)
|
||||
// pv := runtime.mapaccess1(typeOf(data), data, pk)
|
||||
// value := *(*int)(pv)
|
||||
}
|
||||
13
lessons/maps/range_by_map/main.go
Normal file
13
lessons/maps/range_by_map/main.go
Normal file
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
data := map[int]int{1: 1, 2: 2, 3: 3}
|
||||
for _, value := range data {
|
||||
value = 1000
|
||||
_ = value
|
||||
}
|
||||
|
||||
fmt.Println(data)
|
||||
}
|
||||
25
lessons/maps/reservation/comparison_test.go
Normal file
25
lessons/maps/reservation/comparison_test.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
// go test -bench=. comparison_test.go
|
||||
|
||||
func BenchmarkWithoutReservation(b *testing.B) {
|
||||
sourseData := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}
|
||||
for i := 0; i < b.N; i++ {
|
||||
lookup := make(map[int]struct{})
|
||||
for j := 0; j < len(sourseData); j++ {
|
||||
lookup[j] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithReservation(b *testing.B) {
|
||||
sourseData := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}
|
||||
for i := 0; i < b.N; i++ {
|
||||
lookup := make(map[int]struct{}, len(sourseData))
|
||||
for j := 0; j < len(sourseData); j++ {
|
||||
lookup[j] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
lessons/maps/update_during_iteration/main.go
Normal file
25
lessons/maps/update_during_iteration/main.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Need to show solution with maps.Clone
|
||||
|
||||
func main() {
|
||||
data := map[int]struct{}{
|
||||
0: {},
|
||||
1: {},
|
||||
2: {},
|
||||
}
|
||||
|
||||
for key := range data {
|
||||
data[10+key] = struct{}{}
|
||||
}
|
||||
|
||||
for key := range data {
|
||||
fmt.Print(key)
|
||||
fmt.Print(" ")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(data)
|
||||
}
|
||||
22
lessons/maps/update_value/main.go
Normal file
22
lessons/maps/update_value/main.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
type client struct {
|
||||
name string
|
||||
surname string
|
||||
}
|
||||
|
||||
func updateSurname(data map[int]client, id int, surname string) {
|
||||
object := data[id] // copy
|
||||
object.surname = surname
|
||||
data[id] = object // copy
|
||||
|
||||
// data[id].surname = surname -> compilation error
|
||||
}
|
||||
|
||||
func updateSurnameByPointer(data map[int]*client, id int, surname string) {
|
||||
data[id].surname = surname
|
||||
}
|
||||
|
||||
func updateSurnamesSlice(data map[int][]string, id int, surname string) {
|
||||
data[id][5] = surname
|
||||
}
|
||||
Reference in New Issue
Block a user