Maps

作者: bocsoft | 来源:发表于2018-11-30 10:29 被阅读0次

    声明 map 的方式有点儿类似于数组。不同之处是,它以 map 关键字开头,需要两种类型。第一个是键的类型,写在 [] 中。第二个是值的类型,跟在 [] 之后。
    键的类型很特别,它只能是一个可比较的类型,因为如果不能判断两个键是否相等,我们就无法确保我们得到的是正确的值。
    另一方面,值的类型可以是任意类型,它甚至可以是另一个 map。

    Error 类型可以使用 .Error() 方法转换为字符串。

    Map 有一个有趣的特性,不使用指针传递你就可以修改它们。这是因为 map 是引用类型。这意味着它拥有对底层数据结构的引用,就像指针一样。它底层的数据结构是 hash table 或 hash map。
    Map 作为引用类型是非常好的,因为无论 map 有多大,都只会有一个副本。
    如果值已存在,map 不会抛出错误。相反,它们将继续并使用新提供的值覆盖该值。

    引用类型

    Map 有一个有趣的特性,不使用指针传递你就可以修改它们。这是因为 map 是引用类型。这意味着它拥有对底层数据结构的引用,就像指针一样。它底层的数据结构是 hash tablehash map,你可以在这里阅读有关 hash tables 的更多信息。

    Map 作为引用类型是非常好的,因为无论 map 有多大,都只会有一个副本。

    引用类型引入了 maps 可以是 nil 值。如果你尝试使用一个 nil 的 map,你会得到一个 nil 指针异常,这将导致程序终止运行。

    由于 nil 指针异常,你永远不应该初始化一个空的 map 变量:

    var m map[string]string
    

    相反,你可以像我们上面那样初始化空 map,或使用 make 关键字创建 map:

    dictionary =  map[string]string{}
    // OR
    dictionary =  make(map[string]string)
    
    

    这两种方法都可以创建一个空的 hash map 并指向 dictionary。这确保永远不会获得 nil 指针异常

    package main
    
    const (
        //ErrNotFound means the definition could not be found for the given word
        ErrNotFound = DictionaryErr("could not find the word you were looking for")
        //ErrWordExists means you are trying to add a word that is already known
        ErrWordExists = DictionaryErr("cannot add word because it already exists")
        //ErrWordDoesNotExist occurs when trying to update a word not in the dictionary
        ErrWordDoesNotExist = DictionaryErr("cannot update word because it does not exist")
    )
    
    //自定义错误类型
    type DictionaryErr string
    
    func (e DictionaryErr) Error() string {
        return string(e)
    }
    
    //Dictionary store definitions to words
    type Dictionary map[string]string
    
    //Search find a word in the dictionary
    func (d Dictionary) Search(word string) (string, error) {
        definition, ok := d[word]
        if !ok {
            return "", ErrNotFound
        }
        return definition, nil
    }
    
    // Add inserts a word and definition into the dictionary
    func (d Dictionary) Add(word, definition string) error {
        _, err := d.Search(word)
        switch err {
        case ErrNotFound:
            d[word] = definition
        case nil:
            return ErrWordExists
        default:
            return err
        }
        return nil
    }
    
    //Update changes the definition of a given word
    func (d Dictionary) Update(word, definition string) error {
        _, err := d.Search(word)
        switch err {
        case ErrNotFound:
            return ErrWordDoesNotExist
        case nil:
            d[word] = definition
        default:
            return err
        }
        return nil
    }
    
    // Delete removes a word from the dictionary
    func (d Dictionary) Delete(word string) {
        delete(d, word)
    }
    
    
    
    package main
    
    import (
        "testing"
    )
    
    func TestSearch(t *testing.T) {
        dictionary := Dictionary{"test": "this is just a test"}
    
        t.Run("known word", func(t *testing.T) {
            got, _ := dictionary.Search("test")
            want := "this is just a test"
    
            assertStrings(t, got, want)
        })
    
        t.Run("unknown word", func(t *testing.T) {
            _, got := dictionary.Search("unknown")
    
            assertError(t, got, ErrNotFound)
        })
    }
    
    func TestAdd(t *testing.T) {
        t.Run("new word", func(t *testing.T) {
            dictionary := Dictionary{}
            word := "test"
            definition := "this is just a test"
    
            err := dictionary.Add(word, definition)
    
            assertError(t, err, nil)
            assertDefinition(t, dictionary, word, definition)
        })
    
        t.Run("existing word", func(t *testing.T) {
            word := "test"
            definition := "this is just a test"
            dictionary := Dictionary{word: definition}
            err := dictionary.Add(word, "new test")
    
            assertError(t, err, ErrWordExists)
            assertDefinition(t, dictionary, word, definition)
        })
    }
    
    func TestUpdate(t *testing.T) {
        t.Run("existing word", func(t *testing.T) {
            word := "test"
            definition := "this is just a test"
            newDefinition := "new definition"
            dictionary := Dictionary{word: definition}
            err := dictionary.Update(word, newDefinition)
    
            assertError(t, err, nil)
            assertDefinition(t, dictionary, word, newDefinition)
        })
    
        t.Run("new word", func(t *testing.T) {
            word := "test"
            definition := "this is just a test"
            dictionary := Dictionary{}
    
            err := dictionary.Update(word, definition)
            assertError(t, err, ErrWordDoesNotExist)
        })
    }
    
    func TestDelete(t *testing.T) {
        word := "test"
        dictionary := Dictionary{word: "test definition"}
    
        dictionary.Delete(word)
    
        _, err := dictionary.Search(word)
    
        if err != ErrNotFound {
            t.Errorf("Expected '%s' to be deleted", word)
        }
    }
    func assertStrings(t *testing.T, got, want string) {
        t.Helper()
    
        if got != want {
            t.Errorf("got '%s' want '%s'", got, want)
        }
    }
    
    func assertError(t *testing.T, got, want error) {
        t.Helper()
    
        if got != want {
            t.Errorf("got error '%s' want '%s'", got, want)
        }
    }
    
    func assertDefinition(t *testing.T, dictionary Dictionary, word, definition string) {
        t.Helper()
    
        got, err := dictionary.Search(word)
        if err != nil {
            t.Fatal("should find added word:", err)
        }
        if definition != got {
            t.Errorf("got '%s' want '%s'", got, definition)
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Maps

          本文链接:https://www.haomeiwen.com/subject/femccqtx.html