键
视为单词,将值
视为定义。难道还有比构建我们自己的字典更好的学习 map 的方式吗?dictionary_test.go
中编写代码:map
关键字开头,需要两种类型。第一个是键的类型,写在 []
中。第二个是值的类型,跟在 []
之后。go test
后编译器会提示失败信息 ./dictionary_test.go:8:9: undefined: Search
。dictionary.go
中:dictionary_test.go:12: got '' want 'this is just a test' given, 'test'
。map[key]
的方式。assertStrings
辅助函数并删除 given
的部分让实现更通用。Search
方法改进字典的使用。dictionary_test.go
中:Dictionary
类型了,但是我们还没有定义它。然后要在 Dictionary
实例上调用 Search
方法。assertStrings
。dictionary.go
中:Dictionary
类型,它是对 map
的简单封装。定义了自定义类型后,我们可以创建 Search
方法。Error
类型。Error
类型可以使用 .Error()
方法转换为字符串,我们将其传递给断言时会执行此操作。我们也用 if
来保护 assertStrings
,以确保我们不在 nil
上调用 .Error()
。dictionary_test.go:22: expected to get an error.
key
。Search
中魔术错误(magic error)。这也会使我们获得更好的测试。ErrNotFound
变量,如果我们将来更改显示错误的文字,测试也不会失败。Search
方法使字典的验证更加容易。dictionary.go
中:map
是引用类型。这意味着它拥有对底层数据结构的引用,就像指针一样。它底层的数据结构是 hash table
或 hash map
,你可以在这里阅读有关 hash tables
的更多信息。maps
可以是 nil
值。如果你尝试使用一个 nil
的 map,你会得到一个 nil 指针异常
,这将导致程序终止运行。nil 指针异常
,你永远不应该初始化一个空的 map 变量:make
关键字创建 map:hash map
并指向 dictionary
。这确保永远不会获得 nil 指针异常
。Add
看起来不错。除此之外,我们没有考虑当我们尝试添加的值已经存在时会发生什么!Add
不应修改现有值。它应该只在我们的字典中添加新单词。Add
以返回错误,我们将针对新的错误变量 ErrWordExists
进行验证。我们还修改了之前的测试以检查是否为 nil
错误。Add
返回值。dictionary.go
中:nil
错误。switch
语句来匹配错误。如上使用 switch
提供了额外的安全,以防 Search
返回错误而不是 ErrNotFound
。DictionaryErr
类型来实现 error
接口。你可以在 Dave Cheney 的这篇优秀文章中了解更多相关的细节。简而言之,它使错误更具可重用性和不可变性。Update
与 Create
密切相关,这是下一个需要我们实现的方法。Create
解决问题时就明白了如何处理这个问题。所以让我们实现一个与 Create
非常相似的方法。Create
相同的问题。如果我们传入一个新单词,Update
会将它添加到字典中。Update
以返回 error
值。nil
错误。dictionary
和返回错误时切换之外,这个函数看起来几乎与 Add
完全相同。Update
的新错误的注意事项ErrNotFound
而不添加新错误。但是,更新失败时有更精确的错误通常更好。遇到ErrNotFound
时可以重定向用户,但遇到ErrWordDoesNotExist
时会显示错误消息。
Dictionary
,然后检查该单词是否已被删除。go test
我们得到:delete
。它需要两个参数。第一个是这个 map,第二个是要删除的键。delete
函数不返回任何内容,我们基于相同的概念构建 Delete
方法。由于删除一个不存在的值是没有影响的,与我们的 Update
和 Create
方法不同,我们不需要用错误复杂化 API。