Working With Maps For Key-Value Storage: Utilizing Maps For Dynamic Collections And Efficient Data Access

Overview

This chapter delves into Go’s powerful map data structure, a flexible key-value storage system essential for dynamic collections and efficient data retrieval. You’ll learn the fundamentals of map creation, initialization, and iteration, as well as techniques for updating, deleting, and checking the existence of values. With hands-on exercises, you’ll explore how to handle map errors, avoid common pitfalls, and manipulate complex data types stored in maps. By mastering Go maps, you will efficiently manage dynamic collections and improve your data access strategies.

Working With Maps For Key-Value Storage: Utilizing Maps For Dynamic Collections And Efficient Data Access

A map is an unordered set of values indexed by a unique key.


package main

import "fmt"

func main() {
	beatles := map[string]string{}

	beatles["John"] = "guitar"
	beatles["Paul"] = "bass"
	beatles["George"] = "guitar"
	beatles["Ringo"] = "drums"

	fmt.Println(beatles)
}

Initializing Maps

Maps can have their values assigned at creation time, just like arrays.


package main

import "fmt"

func main() {
	beatles := map[string]string{
		"John":   "guitar",
		"Paul":   "bass",
		"George": "guitar",
		"Ringo":  "drums",
	}

	fmt.Println(beatles)
}

Uninitialized Maps

You can initialize maps two different ways:


emails := map[string]string{
	"cory@gopherguides.com": "Cory LaNou",
	"mark@gopherguides.com": "Mark Bates",
	"tim@gopherguides.com":  "Tim Raymond",
}

var emails map[string]string
emails = make(map[string]string)
emails["cory@gopherguides.com"] = "Cory LaNou"
emails["mark@gopherguides.com"] = "Mark Bates"
emails["tim@gopherguides.com"] = "Tim Raymond"

If you don’t initialize them, and try to assign the values, you will receive a runtime error:


var emails map[string]string
emails["cory@gopherguides.com"] = "Cory LaNou"
panic: assignment to entry in nil map

Length And Capacity

The len function can be used to find the length (the number of keys) in the map.

fmt.Println(len(beatles))

Maps don’t have a capacity, since they can grow as needed, so the cap function would raise an error.

fmt.Println(cap(beatles))
error: invalid argument beatles (type map[string]string) for cap

Map Values

Map values can be set and retrieved using the the [] syntax.


package main

import "fmt"

func main() {
	beatles := map[string]string{}

	beatles["Paul"] = "bass"

	paul := beatles["Paul"]
	fmt.Println(paul) // bass
}

Iterating Maps

Maps can be iterated over in the same ways as arrays and slices.


for key, value := range beatles {
	fmt.Printf("%s plays %s\n", key, value)
}

// John plays guitar
// Paul plays bass
// George plays guitar
// Ringo plays drums

The range keyword, in the case of maps, returns the key and the value for each entry in the map.

NOTE: When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next.

Common Mistake: Relying On Map Iteration Order

Maps in Go are intentionally unordered. The iteration order is randomized on purpose to prevent developers from depending on it. This is one of the most common sources of bugs, especially in testing and output generation.

The Problem

Map iteration order is not deterministic. The same map can produce different ordering on each run:


func printConfig(cfg map[string]string) {
	for key, value := range cfg {
		fmt.Printf("%s: %s\n", key, value)
	}
}

Output from two iterations in the same run (using Go’s randmapiter debug flag to emphasize the nondeterminism):


# Output captured with GODEBUG=randmapiter=1 (order will vary each run)
Unordered run 1:
host: localhost
port: 8080
username: admin
password: secret

Unordered run 2:
password: secret
host: localhost
port: 8080
username: admin

Sorted iteration:
host: localhost
password: secret
port: 8080
username: admin

Real-World Scenarios Where This Causes Bugs

1. Flaky Tests

Tests that compare output strings will fail randomly:

func TestConfig(t *testing.T) {
    config := map[string]string{"a": "1", "b": "2", "c": "3"}

    var output string
    for k, v := range config {
        output += fmt.Sprintf("%s=%s ", k, v)
    }

    // This test is FLAKY - will fail randomly!
    expected := "a=1 b=2 c=3 "
    if output != expected {
        t.Errorf("got %q, want %q", output, expected)
    }
}

2. Inconsistent Output Generation

Configuration files or reports generated from maps will have different ordering:

// BAD: config.ini will be different every time
func WriteConfig(config map[string]string) {
    for key, value := range config {
        fmt.Fprintf(file, "%s=%s\n", key, value)
    }
}

3. Serialization Issues

JSON/XML output from maps may differ between runs, breaking checksums or comparisons:

// Output order is unpredictable
for key := range data {
    fmt.Fprintf(w, "<item>%s</item>", key)
}

The Solution: Sort Map Keys First

When order matters, extract and sort the keys before iteration:


func printConfigSorted(cfg map[string]string) {
	keys := make([]string, 0, len(cfg))
	for key := range cfg {
		keys = append(keys, key)
	}
	slices.Sort(keys)

	for _, key := range keys {
		fmt.Printf("%s: %s\n", key, cfg[key])
	}
}

Every run produces the same output:


# Output captured with GODEBUG=randmapiter=1 (order will vary each run)
Unordered run 1:
host: localhost
port: 8080
username: admin
password: secret

Unordered run 2:
password: secret
host: localhost
port: 8080
username: admin

Sorted iteration:
host: localhost
password: secret
port: 8080
username: admin

When Order Matters Vs. When It Doesn't

Order matters when:

  • Generating output for users (reports, config files, logs)
  • Writing tests that compare output strings
  • Creating deterministic output (checksums, signatures)
  • Displaying sorted lists in UIs
  • Generating documentation

Order doesn’t matter when:

  • Looking up values by key
  • Checking membership (_, ok := map[key])
  • Accumulating results (counts, sums)
  • Building another map or set
  • Performing operations where order is irrelevant

Complete Example: Fixing A Flaky Test

Before (Flaky):

func TestGenerateConfig(t *testing.T) {
    settings := map[string]string{
        "timeout": "30",
        "retries": "3",
        "debug":   "true",
    }

    output := GenerateConfig(settings)

    // FLAKY: Order is random
    expected := "timeout=30\nretries=3\ndebug=true\n"
    if output != expected {
        t.Errorf("got %q, want %q", output, expected)
    }
}

After (Reliable):

func TestGenerateConfig(t *testing.T) {
    settings := map[string]string{
        "timeout": "30",
        "retries": "3",
        "debug":   "true",
    }

    output := GenerateConfig(settings)

    // RELIABLE: Expected output is sorted
    expected := "debug=true\nretries=3\ntimeout=30\n"
    if output != expected {
        t.Errorf("got %q, want %q", output, expected)
    }
}

func GenerateConfig(settings map[string]string) string {
    // Sort keys for deterministic output
    keys := make([]string, 0, len(settings))
    for k := range settings {
        keys = append(keys, k)
    }
    slices.Sort(keys)

    var result string
    for _, key := range keys {
        result += fmt.Sprintf("%s=%s\n", key, settings[key])
    }
    return result
}

Remember: Never rely on map iteration order. Always sort keys when order matters.

Map Keys

Map keys must be comparable.

You can’t use functions, maps, or slices as the keys in your maps.


m := map[func()]string{}
fmt.Println(m)

Results in the following error:

./map-keys.go:6: invalid map key type func()

Some structs are ok, but again, can’t contain complex types:


type simple struct {
	ID int
}

type complex struct {
	f func(id int) simple
}

func main() {
	m := map[simple]string{}

	fmt.Println(m)

	// invalid map key type complex
	m1 := map[complex]string{}
}

Deleting Keys From A Map

The delete function can be used to remove a key, and its value, from a map.


package main

import "fmt"

func main() {
	beatles := map[string]string{
		"John":   "guitar",
		"Paul":   "bass",
		"George": "guitar",
		"Ringo":  "drums",
	}

	delete(beatles, "John")

	fmt.Println(beatles)
	// map[Paul:bass George:guitar Ringo:drums]
}

Checking Map Values

Maps in Go return an optional second argument that will tell you if the key exists in the map.


key := "Paul"

value, ok := beatles[key]
if ok {
	fmt.Printf("Found key %q: %q", key, value) // Found Key "Paul": "bass"
} else {
	fmt.Printf("Key not found: %q", key) // Key not found: "foo"
}

// Change the "key" to "foo" and re-run the example

Which can, and will often be, simplified as the following:


key := "Paul"

if value, ok := beatles[key]; ok {
	fmt.Printf("Found key %q: %q", key, value) // Found Key "Paul": "bass"
} else {
	fmt.Printf("Key not found: %q", key) // Key not found: "foo"
}

// Change the "key" to "foo" and re-run the example

Bug Time

In the following example, we show that even if we don’t get an error, you still have a bug because we didn’t check for the existence of the value


type simple struct {
	ID   int
	Name string
}

func main() {
	data := map[int]simple{}
	s1 := simple{ID: 1, Name: "Cory"}
	data[1] = s1

	value := data[10]

	// Because of the way Zero values in Go work,
	// we still get an `zero` value representation of the struct
	// which is certainly a bug in production
	fmt.Printf("%+v", value)
}

Desired output:


{ID:1 Name:Cory}

Actual Output:


{ID:0 Name:}

Bug Solution

Be sure to check for the existence of the key in your code to avoid zero value being being returned and creating a bug:


type simple struct {
	ID   int
	Name string
}

func main() {
	data := map[int]simple{}
	s1 := simple{ID: 1, Name: "Cory"}
	data[1] = s1

	if value, ok := data[10]; ok {
		fmt.Printf("%+v", value)
		return
	}
	fmt.Println("value not found")
}

Exploiting Zero Value

There may be times when the zero value is ok.


counts := make(map[string]int)

sentence := "The quick brown fox jumps over the lazy dog"

words := strings.Fields(strings.ToLower(sentence))

for _, w := range words {
	counts[w]++
}

Because the zero value for any lookup is 0, we can safely use the increment operator and it will then set the initial key/value.

The value of the map will be:


map[brown:1 dog:1 fox:1 jumps:1 lazy:1 over:1 quick:1 the:2]

Testing Presence Only

There may be times when you don’t want the value and only want to test for presence. You can use the _ (underscore) operator to ignore the value in these situations:



words := map[string]int{
	"brown": 1,
	"dog":   1,
	"fox":   1,
	"jumps": 1,
	"lazy":  1,
	"over":  1,
	"quick": 1,
	"the":   2,
}

_, exists := words["foo"]

fmt.Println(exists)

Output:


false

Maps And Complex Values

Storing complex values (such as structs) in a map is a very common operation. However, updating those structs is not completely straightforward.

It may seem intutive to simply assign a new value to a struct via a map lookup:


type simple struct {
	ID   int
	Name string
}

func main() {
	data := map[int]simple{}
	s1 := simple{ID: 1, Name: "Cory"}
	data[1] = s1

	data[1].Name = "Jill" // <== Update the struct

	fmt.Printf("%+v", data)
}

Output:


./main.go:16:15: cannot assign to struct field data[1].Name in map

Updating Complex Map Values

When updating complex map values, you have to retrieve the value, make your changes, and set it back into the map:


type Beatle struct {
	Name       string
	Instrument string
}

beatles := make(map[string]Beatle)

// Create Beatle dynamically
beatles["John"] = Beatle{Name: "John", Instrument: "guitar"}

// Create Beatle from an instance
b := Beatle{Name: "Paul", Instrument: "bass"}
beatles[b.Name] = b

b = Beatle{Name: "George"}
beatles[b.Name] = b

b = Beatle{Name: "Ringo", Instrument: "Drums"}
beatles[b.Name] = b

// Fix George:

// Lookup George
b, ok := beatles["George"]
if !ok {
	fmt.Println("couldn't find George...")
	return
}

// Update George
b.Instrument = "guitar"

// Update the map with the new value
beatles[b.Name] = b

fmt.Println(beatles)

Output:


map[George:{George guitar} John:{John guitar} Paul:{Paul bass} Ringo:{Ringo Drums}]

Range Bug

It’s important to remember that when you use the range operator, that the loop variables are a copy of the value, and not a reference to the value:


type Beatle struct {
	Name       string
	Instrument string
}

beatles := make(map[string]Beatle)

beatles["John"] = Beatle{Name: "John", Instrument: "guitar"}
beatles["Paul"] = Beatle{Name: "Paul", Instrument: "bass"}
beatles["George"] = Beatle{Name: "George", Instrument: "guitar"}
beatles["Ringo"] = Beatle{Name: "Ringo", Instrument: "drums"}

for _, b := range beatles {
	// `b` is a COPY, and will not update the value stored in the map
	b.Instrument = strings.ToUpper(b.Instrument)
	fmt.Println(b)
}

fmt.Println(beatles)

Ouptut:


{John GUITAR}
{Paul BASS}
{George GUITAR}
{Ringo DRUMS}
map[George:{George guitar} John:{John guitar} Paul:{Paul bass} Ringo:{Ringo drums}]

Range Solution

To ensure you are updating the correct value, always use the key when updating a map:


type Beatle struct {
	Name       string
	Instrument string
}

beatles := make(map[string]Beatle)

beatles["John"] = Beatle{Name: "John", Instrument: "guitar"}
beatles["Paul"] = Beatle{Name: "Paul", Instrument: "bass"}
beatles["George"] = Beatle{Name: "George", Instrument: "guitar"}
beatles["Ringo"] = Beatle{Name: "Ringo", Instrument: "drums"}

for k, b := range beatles {
	b.Instrument = strings.ToUpper(b.Instrument)
	fmt.Println(b)
	// update the map:
	beatles[k] = b
}

fmt.Println(beatles)

Ouptut:


{John GUITAR}
{Paul BASS}
{George GUITAR}
{Ringo DRUMS}
map[George:{George GUITAR} John:{John GUITAR} Paul:{Paul BASS} Ringo:{Ringo DRUMS}]

Copy On Update

When you insert into a map, it takes a copy of what you are inserting, and you no longer have a reference to the value stored in the map.


type Beatle struct {
	Name       string
	Instrument string
}

beatles := make(map[string]Beatle)

b := Beatle{Name: "Paul", Instrument: "bass"}
beatles[b.Name] = b
// change the value after being inserted into the map
b.Instrument = "foo"

fmt.Println("variable:", b)

// retrieve the value from the map
lookup := beatles["Paul"]
fmt.Println("lookup:", lookup)

Ouptut:


variable: {Paul foo}
lookup: {Paul bass}

Getting Map Keys

Go does not provide a way to get just a list of keys, or values, from a map. To do this you must build that list yourself.


package main

import "fmt"

func main() {
	m := map[string]string{
		"foo": "bar",
		"bin": "baz",
		"boo": "woo",
	}

	keys := make([]string, 0, len(m))

	for k := range m {
		keys = append(keys, k)
	}
	fmt.Printf("%+v", keys)
}

The Maps Package

The maps package, added to the standard library in Go 1.23, provides iterator-based helpers for working with maps (Keys, Values, Copy, DeleteFunc, Equal/EqualFunc, All, and more).

Go 1.21 introduced the built-in clear for maps and slices; Go 1.23 added the maps package; Go 1.24 improved large-map performance and shipped weak for memory-efficient structures

Maps.Clone

The maps.Clone function creates a shallow copy of a map. Changes to the cloned map don’t affect the original:


original := map[string]int{
	"Alice":   25,
	"Bob":     30,
	"Charlie": 35,
}

// Clone creates a shallow copy of the map
cloned := maps.Clone(original)

// Modify the cloned map
cloned["Alice"] = 99
cloned["David"] = 40

fmt.Println("Original map:", original)
fmt.Println("Cloned map:  ", cloned)

Maps.Copy

The maps.Copy function copies all key-value pairs from a source map to a destination map. Existing keys in the destination are overwritten:


src := map[string]int{
	"Alice":   25,
	"Bob":     30,
	"Charlie": 35,
}

dst := map[string]int{
	"Bob":  99, // This will be overwritten
	"Eve": 28,  // This will remain
}

fmt.Println("Before copy:")
fmt.Println("  Source:     ", src)
fmt.Println("  Destination:", dst)

// Copy all key-value pairs from src to dst
maps.Copy(dst, src)

fmt.Println("\nAfter copy:")
fmt.Println("  Source:     ", src)
fmt.Println("  Destination:", dst)

Maps.Equal

The maps.Equal function compares two maps for equality. Two maps are equal if they have the same keys and values:


map1 := map[string]int{
	"Alice": 25,
	"Bob":   30,
}

map2 := map[string]int{
	"Bob":   30,
	"Alice": 25,
}

map3 := map[string]int{
	"Alice": 25,
	"Bob":   31, // Different value
}

fmt.Println("map1 == map2:", maps.Equal(map1, map2))
fmt.Println("map1 == map3:", maps.Equal(map1, map3))

Maps.DeleteFunc

The maps.DeleteFunc function deletes all key-value pairs that satisfy a predicate function:


scores := map[string]int{
	"Alice":   85,
	"Bob":     92,
	"Charlie": 78,
	"David":   45,
	"Eve":     67,
}

fmt.Println("Before DeleteFunc:", scores)

// Delete all entries where the score is below 70
maps.DeleteFunc(scores, func(name string, score int) bool {
	return score < 70
})

fmt.Println("After DeleteFunc: ", scores)

Maps.Keys

The maps.Keys function returns an iterator over the keys of a map, so you can build a slice (or range directly) without writing a manual loop:


m := map[string]int{
	"Alice":   25,
	"Bob":     30,
	"Charlie": 35,
}

// Get an iterator over the keys, then collect and sort for stable output
keys := maps.Keys(m)
keySlice := slices.Collect(keys)
slices.Sort(keySlice)

fmt.Println("Keys:", keySlice)

Maps.Values

The maps.Values function returns an iterator over the values of a map:


m := map[string]int{
	"Alice":   25,
	"Bob":     30,
	"Charlie": 35,
}

// Get an iterator over the values, then collect and sort for stable output
values := maps.Values(m)
valueSlice := slices.Collect(values)
slices.Sort(valueSlice)

fmt.Println("Values:", valueSlice)

Sorting Maps

As you recall, we covered earlier that maps are not sorted. Given the following code:


func main() {
	months := map[int]string{
		1:  "January",
		2:  "February",
		3:  "March",
		4:  "April",
		5:  "May",
		6:  "June",
		7:  "July",
		8:  "August",
		9:  "September",
		10: "October",
		11: "November",
		12: "December",
	}

	for k, v := range months {
		fmt.Println(k, v)
	}

}

You will receive the following output:


$ go run ./keys-unsorted.go
6 June
8 August
12 December
9 September
10 October
1 January
2 February
3 March
4 April
5 May
7 July
11 November

Sorting By Key

If you want to sort the map by the key, gather the keys, and use the sort package to sort the keys:


func main() {
	months := map[int]string{
		1:  "January",
		2:  "February",
		3:  "March",
		4:  "April",
		5:  "May",
		6:  "June",
		7:  "July",
		8:  "August",
		9:  "September",
		10: "October",
		11: "November",
		12: "December",
	}

	keys := make([]int, 0, len(months))

	for k := range months {
		keys = append(keys, k)
	}
	sort.Ints(keys)
	fmt.Printf("keys: %+v\n", keys)
	for _, k := range keys {
		fmt.Println(k, months[k])
	}
}

And now you can use the sorted slice you created to iterate back through the map in the order you created:


keys: [1 2 3 4 5 6 7 8 9 10 11 12]
1 January
2 February
3 March
4 April
5 May
6 June
7 July
8 August
9 September
10 October
11 November
12 December

Sorting By Value

Sorting by value is a little more complex. The easiest way is to invert the map so you have the values as keys, and then do normal pattern of sorting by key.


func main() {
	words := map[int]string{
		0:  "time",
		1:  "person",
		2:  "year",
		3:  "way",
		4:  "day",
		5:  "thing",
		6:  "man",
		7:  "world",
		8:  "life",
		9:  "hand",
		10: "part",
		12: "child",
		13: "eye",
		14: "woman",
		15: "place",
		16: "work",
		17: "week",
		18: "case",
		19: "point",
		20: "government",
		21: "company",
		22: "number",
		23: "group",
		24: "problem",
		25: "fact",
	}

	// create an inverted map where values are now the keys
	sorted := make(map[string]int)

	keys := make([]string, 0, len(words))

	for k, v := range words {
		keys = append(keys, v)
		sorted[v] = k
	}

	sort.Strings(keys)
	for _, k := range keys {
		fmt.Println(sorted[k], k)
	}
}

And now you can use the sorted slice you created to iterate back through the map in the order you created:


18 case
12 child
21 company
4 day
13 eye
25 fact
20 government
23 group
9 hand
8 life
6 man
22 number
10 part
1 person
15 place
19 point
24 problem
5 thing
0 time
3 way
17 week
14 woman
16 work
7 world
2 year

Maps And Concurrency

Maps are NOT concurrent safe! This is important to know, as it can be the cause of many bugs.


package main

func main() {
	numbers := map[int]int{}
	for i := 0; true; i++ {
		go func(i int) {
			numbers[i] = i
		}(i)
	}
}
goroutine 6906 [runnable]:
main.main.func1(0xc420014180, 0xc42000e0d8)
 ./src/maps-threaded.go:6
created by main.main
 ./src/maps-threaded.go:8 +0x9e

The topic of maps and concurrency, and how to protect maps, will be covered in a different module.

For now it is best to remember that maps are NOT concurrent safe.

NOTE: As of Go 1.9, there is now a sync.Map available which in some cases may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.

Reference Articles

Exercise (15 Mins)


package main

func main() {

	beatles := map[string]string{}

	beatles["John"] = "guitar"
	beatles["Paul"] = "bass"
	beatles["George"] = "guitar"
	beatles["Ringo"] = "drums"

	// Loop through the map and print out the key and value

	// Look up the key `Bob` and detect that it wasn't found by printing `not found`

	// Declare a slice of strings called `keys` and collect all the keys from the map.

	// sort the keys

	// print out the keys

	// print out the sorted map

}

Solution


package main

import (
	"fmt"
	"sort"
)

func main() {

	beatles := map[string]string{}

	beatles["John"] = "guitar"
	beatles["Paul"] = "bass"
	beatles["George"] = "guitar"
	beatles["Ringo"] = "drums"

	// Loop through the map and print out the key and value

	for key, value := range beatles {
		fmt.Printf("key: %q, value: %q\n", key, value)
	}

	// Look up the key `Bob` and detect that it wasn't found by printing `not found`
	if bob, ok := beatles["Bob"]; !ok {
		fmt.Println("not found")
	} else {
		fmt.Println(bob)
	}

	// Declare a slice of strings called `keys` and collect all the keys from the map.
	keys := []string{}
	for k := range beatles {
		keys = append(keys, k)
	}

	// sort the keys
	sort.Strings(keys)

	// print out the keys
	fmt.Println(keys)

	// print out the sorted map
	for _, k := range keys {
		fmt.Println(k, beatles[k])
	}
}

Output:


key: "John", value: "guitar"
key: "Paul", value: "bass"
key: "George", value: "guitar"
key: "Ringo", value: "drums"
not found
[George John Paul Ringo]
George guitar
John guitar
Paul bass
Ringo drums

Stretch Exercise

During a data import, the first and last names were incorrectly combined.

map[1:{1 Cory Bates} 2:{2 Mark Raymond} 3:{3 Tim LaNou}]

Using your knowledge of maps, write the code to manually correct the names in the map.


package main

import "fmt"

type User struct {
	ID   int
	Name string
}

func main() {
	users := make(map[int]User)

	u := User{ID: 1, Name: "Cory Bates"}
	users[u.ID] = u

	u = User{ID: 2, Name: "Mark Raymond"}
	users[u.ID] = u

	u = User{ID: 3, Name: "Tim LaNou"}
	users[u.ID] = u

	// Look up Cory

	// Update Cory's name to "Cory LaNou"

	// Set the user of ID `1` to the updated user

	// Fix the remaining users names:
	// ID:2, Mark -> "Mark Bates"
	// ID:3, Tim -> "Tim Raymond"

	fmt.Println(users)
}

Solution


package main

import "fmt"

type User struct {
	ID   int
	Name string
}

func main() {
	users := make(map[int]User)

	u := User{ID: 1, Name: "Cory Bates"}
	users[u.ID] = u

	u = User{ID: 2, Name: "Mark Raymond"}
	users[u.ID] = u

	u = User{ID: 3, Name: "Tim LaNou"}
	users[u.ID] = u

	// Look up Cory
	u = users[1]

	// Update Cory's name to "Cory LaNou"
	u.Name = "Cory LaNou"

	// Set the user of ID `1` to the updated user
	users[u.ID] = u

	// Fix the remaining users names:
	// ID:2, Mark -> "Mark Bates"
	// ID:3, Tim -> "Tim Raymond"

	u = users[2]
	u.Name = "Mark Bates"
	users[u.ID] = u

	u = users[3]
	u.Name = "Tim Raymond"
	users[u.ID] = u

	fmt.Println(users)
}