Problem overview
The function addContact receives a phone book, phoneBook, which is a map[string]string from names to phone numbers, plus a name and a number. It adds the contact and returns the phone book, but only when name isn't in the phone book yet. A name that is already there keeps its old number.
For a book with Ana and Ben and the new name Cara, the result has all three. For Ben with a new number, the result is unchanged, and Ben keeps 555-0199. For an empty book and Max, the result has one contact. The order of the entries doesn't matter: a Go map has no order of its own.
Approach
A plain assignment, phoneBook[name] = number, would add a missing name, but it would also overwrite an existing one. So first ask whether the name is a key. The comma-ok lookup answers that, and it is the right tool because it tells a missing key from a key that holds an empty string. Skip the value with _ and test !ok, which is true only for a new name.
Step by step
- Write an
ifthat looksnameup with the comma-ok form and runs whenokis false. Put the lookup in theifline, before a;. - Inside it, store the number:
phoneBook[name] = number. For a name already in the book nothing runs, so its old number stays. - After the
if, returnphoneBook.
The solution in Go
func addContact(phoneBook map[string]string, name string, number string) map[string]string {
if _, ok := phoneBook[name]; !ok {
phoneBook[name] = number
}
return phoneBook
}
A map passed to a function is not copied: the function and its caller share the same map. The new contact therefore lands in the caller's map as well, and the returned value is that same map. After res := addContact(orig, "Max", "555-0100") on an empty orig, both len(orig) and len(res) are 1.
Notice that the lookup and the assignment use the same key, name. Because the lookup sits in the if line, ok only exists for that statement. That keeps the check close to the code that depends on it and avoids a leftover variable.
Testing
Printing the returned map for the statement's examples gives:
map[Ana:555-0142 Ben:555-0199 Cara:555-0123]
map[Ana:555-0142 Ben:555-0199]
map[Max:555-0100]
Go's fmt prints maps sorted by key, so the output is stable, even though the map itself has no order.
Edge cases and common mistakes
- Skipping the check. With only
phoneBook["Ben"] = "555-0100", Ben's number becomes555-0100and the old one is lost. - Checking with
phoneBook[name] == "". It works while every stored number is non-empty, but it treats a stored empty string as missing, and it is the wrong habit for maps in general. The comma-ok form is exact. - An empty book.
map[string]string{}works, and the lookup simply reports the name as missing. Anilmap, declared asvar m map[string]string, can be read but not written: adding a contact to it panics withassignment to entry in nil map. The lesson's tests pass real maps. - Same number for two people. Allowed. Only the names are keys.
