From a2cfffcb456470686d9f92536581e1da2d66bbad Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Mon, 15 Jul 2019 23:01:51 -0300 Subject: [PATCH 01/10] =?UTF-8?q?In=C3=ADcio=20de=20tradu=C3=A7=C3=A3o=20d?= =?UTF-8?q?e=20Maps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SUMMARY.md | 1 - maps/v1/dicionario.go | 9 ++++ maps/v1/dicionario_test.go | 20 +++++++++ maps/v1/dictionary.go | 9 ---- maps/v1/dictionary_test.go | 20 --------- primeiros-passos-com-go/maps.md | 76 ++++++++++++++++----------------- 6 files changed, 67 insertions(+), 68 deletions(-) create mode 100644 maps/v1/dicionario.go create mode 100644 maps/v1/dicionario_test.go delete mode 100644 maps/v1/dictionary.go delete mode 100644 maps/v1/dictionary_test.go diff --git a/SUMMARY.md b/SUMMARY.md index bd28fcc4..8c0f9cb6 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -8,7 +8,6 @@ - [Instalação do Go](primeiros-passos-com-go/instalacao-do-go.md) - [Olá, mundo](primeiros-passos-com-go/hello-world.md) - [Inteiros](primeiros-passos-com-go/integers.md) - <<<<<<< HEAD - [Iteração](primeiros-passos-com-go/iteracao.md) - [Arrays e slices](primeiros-passos-com-go/arrays-e-slices.md) - [Structs, métodos e interfaces](primeiros-passos-com-go/structs-methods-and-interfaces.md) diff --git a/maps/v1/dicionario.go b/maps/v1/dicionario.go new file mode 100644 index 00000000..c7a85b9d --- /dev/null +++ b/maps/v1/dicionario.go @@ -0,0 +1,9 @@ +package main + +// Dicionario armazena definições de palavras +type Dicionario map[string]string + +// Busca encontra uma palavra no dicionário +func (d Dicionario) Busca(palavra string) string { + return d[palavra] +} diff --git a/maps/v1/dicionario_test.go b/maps/v1/dicionario_test.go new file mode 100644 index 00000000..0af2a610 --- /dev/null +++ b/maps/v1/dicionario_test.go @@ -0,0 +1,20 @@ +package main + +import "testing" + +func TestBusca(t *testing.T) { + dicionario := map[string]string{"teste": "isso é apenas um teste"} + + resultado := Busca(dicionario, "teste") + esperado := "isso é apenas um teste" + + compararStrings(t, resultado, esperado) +} + +func compararStrings(t *testing.T, resultado, esperado string) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "test") + } +} diff --git a/maps/v1/dictionary.go b/maps/v1/dictionary.go deleted file mode 100644 index 3ed23142..00000000 --- a/maps/v1/dictionary.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -// Dictionary store definitions to words -type Dictionary map[string]string - -// Search find a word in the dictionary -func (d Dictionary) Search(word string) string { - return d[word] -} diff --git a/maps/v1/dictionary_test.go b/maps/v1/dictionary_test.go deleted file mode 100644 index 3493ac38..00000000 --- a/maps/v1/dictionary_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import "testing" - -func TestSearch(t *testing.T) { - dictionary := Dictionary{"test": "this is just a test"} - - got := dictionary.Search("test") - want := "this is just a test" - - assertStrings(t, got, want) -} - -func assertStrings(t *testing.T, got, want string) { - t.Helper() - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } -} diff --git a/primeiros-passos-com-go/maps.md b/primeiros-passos-com-go/maps.md index fa85bb12..3edc5a4b 100644 --- a/primeiros-passos-com-go/maps.md +++ b/primeiros-passos-com-go/maps.md @@ -1,94 +1,94 @@ # Maps -[**You can find all the code for this chapter here**](https://github.com/quii/learn-go-with-tests/tree/master/maps) +[**Você pode encontrar todos os códigos para esse capítulo aqui**](https://github.com/larien/learn-go-with-tests/tree/master/maps) -In [arrays & slices](primeiros-passos-com-go/arrays-e-slices.md), you saw how to store values in order. Now, we will look at a way to store items by a `key` and look them up quickly. +Em [arrays e slices](primeiros-passos-com-go/arrays-e-slices.md), vimos como armazenas valores em ordem. Agora, vamos descobrir uma forma de armazenar itens por uma `chave` (chave) e procurar por ela rapidamente. -Maps allow you to store items in a manner similar to a dictionary. You can think of the `key` as the word and the `value` as the definition. And what better way is there to learn about Maps than to build our own dictionary? +Maps te permitem armazenar itens de forma parecida com a de um dicionário. Você pode pensar na `chave` como a palavra e o `valor` como a definição. E que forma melhor de aprender sobre Maps do que criar seu próprio dicionário? -First, assuming we already have some words with their definitions in the dictionary, if we search for a word, it should return the definition of it. +Primeiro, vamos presumir que já temos algumas palavras com suas definições no dicionário. Se procurarmos por uma palavra, ele deve retornar sua definição. -## Write the test first +## Escreva o teste primeiro -In `dictionary_test.go` +Em `dicionario_test.go` ```go package main import "testing" -func TestSearch(t *testing.T) { - dictionary := map[string]string{"test": "this is just a test"} +func TestBusca(t *testing.T) { + dicionario := map[string]string{"teste": "isso é apenas um teste"} - got := Search(dictionary, "test") - want := "this is just a test" + resultado := Busca(dictionary, "teste") + esperado := "isso é apenas um teste" - if got != want { - t.Errorf("got '%s' want '%s' given, '%s'", got, want, "test") + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "test") } } ``` -Declaring a Map is somewhat similar to an array. Except, it starts with the `map` keyword and requires two types. The first is the key type, which is written inside the `[]`. The second is the value type, which goes right after the `[]`. +Declarar um Map é bem parecido com um array. A diferença é que começa com a palavra-chave `map` e requer dois tipos. O primeiro é o tipo da chave, que é escrito dentro de `[]`. O segundo é o tipo do valor, que vai logo após o `[]`. -The key type is special. It can only be a comparable type because without the ability to tell if 2 keys are equal, we have no way to ensure that we are getting the correct value. Comparable types are explained in depth in the [language spec](https://golang.org/ref/spec#Comparison_operators). +O tipo da chave é especial. Só pode ser um tipo comparável, porque sem a habilidade de dizer se duas chaves são iguais, não temos como certificar de que estamos obtendo o valor correto. Tipos comparáveis são explicados com detalhes na [especificação da linguagem](https://golang.org/ref/spec#Comparison_operators). -The value type, on the other hand, can be any type you want. It can even be another map. +O tipo do valor, por outro lado, pode ser o tipo que quiser. Pode até ser outro map. -Everything else in this test should be familiar. +O restante do teste já deve ser familiar para você. -## Try to run the test +## Execute o teste -By running `go test` the compiler will fail with `./dictionary_test.go:8:9: undefined: Search`. +Ao executar `go test`, o compilador vai falhar com `./dicionario_test.go:8:9: undefined: Busca`. -## Write the minimal amount of code for the test to run and check the output +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste falhado -In `dictionary.go` +Em `dicionario.go`: ```go package main -func Search(dictionary map[string]string, word string) string { +func Busca(dicionario map[string]string, palavra string) string { return "" } ``` -Your test should now fail with a _clear error message_ +Agora seu teste vai falhar com uma _mensagem de erro clara_: -`dictionary_test.go:12: got '' want 'this is just a test' given, 'test'`. +`dicionario_test.go:12: resultado '', esperado 'isso é apenas um teste', dado 'teste'`. -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar ```go -func Search(dictionary map[string]string, word string) string { - return dictionary[word] +func Busca(dicionario map[string]string, palavra string) string { + return dicionario[palavra] } ``` -Getting a value out of a Map is the same as getting a value out of Array `map[key]`. +Obter um valor de um Map é igual a obter um valor de um Array: `map[chave]`. -## Refactor +## Refatoração ```go -func TestSearch(t *testing.T) { - dictionary := map[string]string{"test": "this is just a test"} +func TestBusca(t *testing.T) { + dicionario := map[string]string{"teste": "isso é apenas um teste"} - got := Search(dictionary, "test") - want := "this is just a test" + resultado := Busca(dicionario, "teste") + esperado := "isso é apenas um teste" - assertStrings(t, got, want) + compararStrings(t, resultado, esperado) } -func assertStrings(t *testing.T, got, want string) { - t.Helper() +func compararStrings(t *testing.T, resultado, esperado string) { + t.Helper() - if got != want { - t.Errorf("got '%s' want '%s'", got, want) + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "test") } } ``` -I decided to create an `assertStrings` helper to make the implementation more general. +Decidi criar um helper `compararStrings` para tornar a implementação mais genérica. ### Using a custom type From 5a0e8f67ca20942265793f9aa7c9aeb565209a2f Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Tue, 16 Jul 2019 22:36:28 -0300 Subject: [PATCH 02/10] =?UTF-8?q?Mais=20um=20pouco=20de=20tradu=C3=A7?= =?UTF-8?q?=C3=A3o=20com=20tipos=20personalizados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maps/v1/dicionario_test.go | 12 +++--- maps/v2/dicionario.go | 19 ++++++++++ maps/v2/dicionario_test.go | 36 ++++++++++++++++++ maps/v2/dictionary.go | 19 ---------- maps/v2/dictionary_test.go | 38 ------------------- primeiros-passos-com-go/maps.md | 67 ++++++++++++++++----------------- 6 files changed, 93 insertions(+), 98 deletions(-) create mode 100644 maps/v2/dicionario.go create mode 100644 maps/v2/dicionario_test.go delete mode 100644 maps/v2/dictionary.go delete mode 100644 maps/v2/dictionary_test.go diff --git a/maps/v1/dicionario_test.go b/maps/v1/dicionario_test.go index 0af2a610..08969a01 100644 --- a/maps/v1/dicionario_test.go +++ b/maps/v1/dicionario_test.go @@ -3,18 +3,18 @@ package main import "testing" func TestBusca(t *testing.T) { - dicionario := map[string]string{"teste": "isso é apenas um teste"} + dicionario := Dicionario{"teste": "isso é apenas um teste"} - resultado := Busca(dicionario, "teste") - esperado := "isso é apenas um teste" + resultado := dicionario.Busca("teste") + esperado := "isso é apenas um teste" - compararStrings(t, resultado, esperado) + compararStrings(t, resultado, esperado) } func compararStrings(t *testing.T, resultado, esperado string) { t.Helper() if resultado != esperado { - t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "test") - } + t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "test") + } } diff --git a/maps/v2/dicionario.go b/maps/v2/dicionario.go new file mode 100644 index 00000000..ccec53ff --- /dev/null +++ b/maps/v2/dicionario.go @@ -0,0 +1,19 @@ +package main + +import "errors" + +// Dicionario armazena definições de palavras +type Dicionario map[string]string + +// ErrNaoEncontrado é a definição para não ter encontrado determinada palavra +var ErrNaoEncontrado = errors.New("não foi possível encontrar a palavra procurada") + +// Busca encontra uma palavra no dicionário +func (d Dicionario) Busca(palavra string) (string, error) { + definicao, ok := d[palavra] + if !ok { + return "", ErrNaoEncontrado + } + + return definicao, nil +} diff --git a/maps/v2/dicionario_test.go b/maps/v2/dicionario_test.go new file mode 100644 index 00000000..e5caf00d --- /dev/null +++ b/maps/v2/dicionario_test.go @@ -0,0 +1,36 @@ +package main + +import "testing" + +func TestBusca(t *testing.T) { + dicionario := Dicionario{"teste": "isso é apenas um teste"} + + t.Run("palavra conhecida", func(t *testing.T) { + resultado, _ := dicionario.Busca("teste") + esperado := "isso é apenas um teste" + + comparaStrings(t, resultado, esperado) + }) + + t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") + + comparaErro(t, resultado, ErrNaoEncontrado) + }) +} + +func comparaStrings(t *testing.T, resultado, esperado string) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaErro(t *testing.T, resultado, esperado error) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado erro '%s', esperado '%s'", resultado, esperado) + } +} diff --git a/maps/v2/dictionary.go b/maps/v2/dictionary.go deleted file mode 100644 index 669129e2..00000000 --- a/maps/v2/dictionary.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import "errors" - -// Dictionary store definitions to words -type Dictionary map[string]string - -// ErrNotFound means the definition could not be found for the given word -var ErrNotFound = errors.New("could not find the word you were looking for") - -// 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 -} diff --git a/maps/v2/dictionary_test.go b/maps/v2/dictionary_test.go deleted file mode 100644 index 5be71f03..00000000 --- a/maps/v2/dictionary_test.go +++ /dev/null @@ -1,38 +0,0 @@ -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 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) - } -} diff --git a/primeiros-passos-com-go/maps.md b/primeiros-passos-com-go/maps.md index 3edc5a4b..f6304f27 100644 --- a/primeiros-passos-com-go/maps.md +++ b/primeiros-passos-com-go/maps.md @@ -90,72 +90,69 @@ func compararStrings(t *testing.T, resultado, esperado string) { Decidi criar um helper `compararStrings` para tornar a implementação mais genérica. -### Using a custom type +### Usando um tipo personalizado -We can improve our dictionary's usage by creating a new type around map and making `Search` a method. +Podemos melhorar o uso do nosso dicionário criando um novo tipo baseado no map e fazendo a `Busca` virar um método. -In `dictionary_test.go`: +Em `dicionario_test.go`: ```go -func TestSearch(t *testing.T) { - dictionary := Dictionary{"test": "this is just a test"} +func TestBusca(t *testing.T) { + dicionario := Dictionary{"teste": "isso é apenas um teste"} - got := dictionary.Search("test") - want := "this is just a test" + resultado := dictionary.Busca("teste") + esperado := "isso é apenas um teste" - assertStrings(t, got, want) + compararStrings(t, resultado, esperado) } ``` -We started using the `Dictionary` type, which we have not defined yet. Then called `Search` on the `Dictionary` instance. +Começamos a usar o tipo `Dicionario`, que ainda não definimos. Depois disso, chamamos `Busca` da instância de `Dicionario`. -We did not need to change `assertStrings`. +Não precisamos mudar o `comparaStrings`. -In `dictionary.go`: +Em `dicionario.go`: ```go -type Dictionary map[string]string +type Dicionario map[string]string -func (d Dictionary) Search(word string) string { - return d[word] +func (d Dicionario) Busca(palavra string) string { + return d[palavra] } ``` -Here we created a `Dictionary` type which acts as a thin wrapper around `map`. With the custom type defined, we can create the `Search` method. +Aqui criamos um tipo `Dicionario` que trabalha em cima da abstração de `map`. Com o tipo personalizado definido, podemos criar o método `Busca`. -## Write the test first +## Escreva o teste primeiro -The basic search was very easy to implement, but what will happen if we supply a word that's not in our dictionary? +A busca básica foi bem fácil de implementar, mas o que acontece se passarmos uma palavra que não está no nosso dicionário? -We actually get nothing back. This is good because the program can continue to run, but there is a better approach. The function can report that the word is not in the dictionary. This way, the user isn't left wondering if the word doesn't exist or if there is just no definition \(this might not seem very useful for a dictionary. However, it's a scenario that could be key in other usecases\). +Como o código está agora, não recebemos nada de volta. Isso é bom porque o programa continua a ser executado, mas há uma abordagem melhor. A função pode reportar que a palavra não está no dicionário. Dessa forma, o usuário não fica se perguntando se a palavra não existe ou se apenas não existe definição para ela (isso pode não parecer tão útil para um dicionário. No entanto, é um caso que pode ser essencial em outros casos de usos). ```go -func TestSearch(t *testing.T) { - dictionary := Dictionary{"test": "this is just a test"} +func TestBusca(t *testing.T) { + dicionario := Dicionario{"teste": "isso é apenas um teste"} - t.Run("known word", func(t *testing.T) { - got, _ := dictionary.Search("test") - want := "this is just a test" + t.Run("palavra conhecida", func(t *testing.T) { + resultado, _ := dicionario.Busca("teste") + esperado := "isso é apenas um teste" - assertStrings(t, got, want) - }) + comparaStrings(t, resultado, esperado) + }) - t.Run("unknown word", func(t *testing.T) { - _, err := dictionary.Search("unknown") - want := "could not find the word you were looking for" + t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") - if err == nil { - t.Fatal("expected to get an error.") + if err == nil { + t.Fatal("é esperado que um erro seja obtido.") } - - assertStrings(t, err.Error(), want) - }) + }) } ``` -The way to handle this scenario in Go is to return a second argument which is an `Error` type. +A forma de lidar com esse caso no Go é retornar um segundo argumento que é do tipo `Error`. -`Error`s can be converted to a string with the `.Error()` method, which we do when passing it to the assertion. We are also protecting `assertStrings` with `if` to ensure we don't call `.Error()` on `nil`. +Erros podem ser convertidos para uma string com o método `.Error()`, o que podemos fazer quando passarmos para a asserção. Também estamos protegendo o `comparaStrings` com `if` para certificar que não chamemos `.Error()` quando o erro for `nil`. ## Try and run the test From eb5a5a31aa1338e0811e91125b6502eb7e631e7b Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Mon, 29 Jul 2019 21:06:50 -0300 Subject: [PATCH 03/10] =?UTF-8?q?Tradu=C3=A7=C3=A3o=20at=C3=A9=20tipos=20r?= =?UTF-8?q?efer=C3=AAncia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maps/v3/dicionario.go | 24 +++++ maps/v3/dicionario_test.go | 61 ++++++++++++ maps/v3/dictionary.go | 24 ----- maps/v3/dictionary_test.go | 61 ------------ primeiros-passos-com-go/maps.md | 168 ++++++++++++++++---------------- 5 files changed, 171 insertions(+), 167 deletions(-) create mode 100644 maps/v3/dicionario.go create mode 100644 maps/v3/dicionario_test.go delete mode 100644 maps/v3/dictionary.go delete mode 100644 maps/v3/dictionary_test.go diff --git a/maps/v3/dicionario.go b/maps/v3/dicionario.go new file mode 100644 index 00000000..f0cff389 --- /dev/null +++ b/maps/v3/dicionario.go @@ -0,0 +1,24 @@ +package main + +import "errors" + +// Dicionario armazena definições de palavras +type Dicionario map[string]string + +// ErrNaoEncontrado significa que a definição não pôde ser encontrada para determinada palavra +var ErrNaoEncontrado = errors.New("não foi possível encontrar a palavra que você procura") + +// Busca encontra uma palavra no dicionário +func (d Dicionario) Busca(palavra string) (string, error) { + definicao, existe := d[palavra] + if !existe { + return "", ErrNaoEncontrado + } + + return definicao, nil +} + +// Adiciona insere uma palavra e definição no dicionário +func (d Dicionario) Adiciona(palavra, definicao string) { + d[palavra] = definicao +} diff --git a/maps/v3/dicionario_test.go b/maps/v3/dicionario_test.go new file mode 100644 index 00000000..f1341921 --- /dev/null +++ b/maps/v3/dicionario_test.go @@ -0,0 +1,61 @@ +package main + +import ( + "testing" +) + +func TestSearch(t *testing.T) { + dicionario := Dicionario{"teste": "isso é apenas um teste"} + + t.Run("palavra conhecida", func(t *testing.T) { + resultado, _ := dicionario.Busca("teste") + esperado := "isso é apenas um teste" + + comparaStrings(t, resultado, esperado) + }) + + t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") + + comparaErro(t, resultado, ErrNaoEncontrado) + }) +} + +func TestAdiciona(t *testing.T) { + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" + + dicionario.Adiciona(palavra, definicao) + + comparaDefinicao(t, dicionario, palavra, definicao) +} + +func comparaStrings(t *testing.T, resultado, esperado string) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaErro(t *testing.T, resultado, esperado error) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado erro '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaDefinicao(t *testing.T, dicionario Dicionario, palavra, definicao string) { + t.Helper() + + resultado, err := dicionario.Busca(palavra) + if err != nil { + t.Fatal("deveria ter encontrado palavra adicionada:", err) + } + + if definicao != resultado { + t.Errorf("resultado '%s', esperado '%s'", resultado, definicao) + } +} diff --git a/maps/v3/dictionary.go b/maps/v3/dictionary.go deleted file mode 100644 index 665b6c35..00000000 --- a/maps/v3/dictionary.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import "errors" - -// Dictionary store definitions to words -type Dictionary map[string]string - -// ErrNotFound means the definition could not be found for the given word -var ErrNotFound = errors.New("could not find the word you were looking for") - -// 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) { - d[word] = definition -} diff --git a/maps/v3/dictionary_test.go b/maps/v3/dictionary_test.go deleted file mode 100644 index 2bbc7790..00000000 --- a/maps/v3/dictionary_test.go +++ /dev/null @@ -1,61 +0,0 @@ -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) { - dictionary := Dictionary{} - word := "test" - definition := "this is just a test" - - dictionary.Add(word, definition) - - assertDefinition(t, dictionary, word, definition) -} - -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) - } -} diff --git a/primeiros-passos-com-go/maps.md b/primeiros-passos-com-go/maps.md index f6304f27..82cb7a82 100644 --- a/primeiros-passos-com-go/maps.md +++ b/primeiros-passos-com-go/maps.md @@ -154,186 +154,190 @@ A forma de lidar com esse caso no Go é retornar um segundo argumento que é do Erros podem ser convertidos para uma string com o método `.Error()`, o que podemos fazer quando passarmos para a asserção. Também estamos protegendo o `comparaStrings` com `if` para certificar que não chamemos `.Error()` quando o erro for `nil`. -## Try and run the test +## Execute o teste + +Isso não vai compilar. This does not compile -```text -./dictionary_test.go:18:10: assignment mismatch: 2 variables but 1 values -``` +`./dictionary_test.go:18:10: assignment mismatch: 2 variables but 1 values` -## Write the minimal amount of code for the test to run and check the output +`incompatibilidade de atribuição: 2 variáveis, mas 1 valor` + +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste falhado ```go -func (d Dictionary) Search(word string) (string, error) { - return d[word], nil +func (d Dicionario) Busca(palavra string) (string, error) { + return d[palavra], nil } ``` -Your test should now fail with a much clearer error message. +Agora seu teste deve falhar com uma mensagem de erro muito mais clara. `dictionary_test.go:22: expected to get an error.` -## Write enough code to make it pass +`erro esperado.` + +## Escreva código o suficiente para fazer o teste passar ```go -func (d Dictionary) Search(word string) (string, error) { - definition, ok := d[word] - if !ok { - return "", errors.New("could not find the word you were looking for") +func (d Dicionario) Busca(palavra string) (string, error) { + definicao, existe := d[palavra] + if !existe { + return "", errors.New("não foi possível encontrar a palavra que você procura") } - return definition, nil + return definicao, nil } ``` -In order to make this pass, we are using an interesting property of the map lookup. It can return 2 values. The second value is a boolean which indicates if the key was found successfully. +Para fazê-lo passar, estamos usando uma propriedade interessante ao percorrer o map. Ele pode retornar dois valores. O segundo valor é uma boleana que indica se a chave foi encontrada com sucesso. -This property allows us to differentiate between a word that doesn't exist and a word that just doesn't have a definition. +Essa propriedade nos permite diferenciar entre uma palavra que não existe e uma palavra que só não tem uma definição. -## Refactor +## Refatoração ```go -var ErrNotFound = errors.New("could not find the word you were looking for") +var ErrNaoEncontrado = errors.New("não foi possível encontrar a palavra que você procura") -func (d Dictionary) Search(word string) (string, error) { - definition, ok := d[word] - if !ok { - return "", ErrNotFound +func (d Dicionario) Busca(palavra string) (string, error) { + definicao, existe := d[palavra] + if !existe { + return "", ErrNaoEncontrado } - return definition, nil + return definicao, nil } ``` -We can get rid of the magic error in our `Search` function by extracting it into a variable. This will also allow us to have a better test. +Podemos nos livrar do "erro mágico" na nossa função de `Busca` extraindo-o para dentro de uma variável. Isso também nos permite ter um teste melhor. ```go -t.Run("unknown word", func(t *testing.T) { - _, got := dictionary.Search("unknown") +t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") - assertError(t, got, ErrNotFound) + comparaErro(t, resultado, ErrNotFound) }) -func assertError(t *testing.T, got, want error) { +func comparaErro(t *testing.T, resultado, esperado error) { t.Helper() - if got != want { - t.Errorf("got error '%s' want '%s'", got, want) + if resultado != esperado { + t.Errorf("resultado erro '%s', esperado '%s'", resultado, esperado) } } ``` -By creating a new helper we were able to simplify our test, and start using our `ErrNotFound` variable so our test doesn't fail if we change the error text in the future. +Conseguimos simplificar nosso teste criando um novo helper e começando a usar nossa variável `ErrNaoEncontrado` para que nosso teste não falhe se mudarmos o texto do erro no futuro. -## Write the test first +## Escreva o teste primeiro -We have a great way to search the dictionary. However, we have no way to add new words to our dictionary. +Temos uma ótima maneira de buscar no dicionário. No entanto, não temos como adicionar novas palavras nele. ```go -func TestAdd(t *testing.T) { - dictionary := Dictionary{} - dictionary.Add("test", "this is just a test") +func TestAdiciona(t *testing.T) { + dicionario := Dicionario{} + dicionario.Adiciona("teste", "isso é apenas um teste") - want := "this is just a test" - got, err := dictionary.Search("test") + esperado := "isso é apenas um teste" + resultado, err := dicionario.Busca("teste") if err != nil { - t.Fatal("should find added word:", err) + t.Fatal("não foi possível encontrar a palavra adicionada:", err) } - if want != got { - t.Errorf("got '%s' want '%s'", got, want) + if esperado != resultado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) } } ``` -In this test, we are utilizing our `Search` function to make the validation of the dictionary a little easier. +Nesse teste, estamos utilizando nossa função `Busca` para tornar a validação do dicionário um pouco mais fácil. -## Write the minimal amount of code for the test to run and check output +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste falhado -In `dictionary.go` +Em `dicionario.go` ```go -func (d Dictionary) Add(word, definition string) { +func (d Dicionario) Adiciona(palavra, definicao string) { } ``` -Your test should now fail +Agora seu teste deve falhar. -```text -dictionary_test.go:31: should find added word: could not find the word you were looking for +```bash +dicionario_test.go:31: deveria ter encontrado palavra adicionada: não foi possível encontrar a palavra que você procura ``` -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar ```go -func (d Dictionary) Add(word, definition string) { - d[word] = definition +func (d Dicionario) Adiciona(palavra, definicao string) { + d[palavra] = definicao } ``` -Adding to a map is also similar to an array. You just need to specify a key and set it equal to a value. +Adicionar coisas a um map também é bem semelhante a um array. Você só precisar especificar uma chave e definir qual é seu valor. -### Reference Types +### Tipos Referência -An interesting property of maps is that you can modify them without passing them as a pointer. This is because `map` is a reference type. Meaning it holds a reference to the underlying data structure, much like a pointer. The underlying data structure is a `hash table`, or `hash map`, and you can read more about `hash tables` [here](https://en.wikipedia.org/wiki/Hash_table). +Uma propriedade interessante dos maps é que você pode modificá-los sem passá-los como ponteiro. Isso é porque o `map` é um tipo referência. Isso significa que ele contém uma referência à estrutura de dado subjacente, assim como um ponteiro. A estrutura de data subjacente é uma `tabela de dispersão` ou `mapa de hash`, e você pode ler mais sobre [aqui](https://pt.wikipedia.org/wiki/Tabela_de_dispers%C3%A3o). -Maps being a reference is really good, because no matter how big a map gets there will only be one copy. +É muito bom referenciar um map, porque não importa o tamanho do map, só vai haver uma cópia. -A gotcha that reference types introduce is that maps can be a `nil` value. A `nil` map behaves like an empty map when reading, but attempts to write to a `nil` map will cause a runtime panic. You can read more about maps [here](https://blog.golang.org/go-maps-in-action). +Um conceito que os tipos referência apresentam é que maps podem ser um valor `nil`. Um map `nil` se comporta como um map vazio durante a leitura,mas tentar inserir coisas em um map `nil` gera um panic em tempo de execução. Você pode saber mais sobre maps [aqui](https://blog.golang.org/go-maps-in-action) (em inglês). -Therefore, you should never initialize an empty map variable: +Além disso, você nunca deve inicializar um map vazio: ```go var m map[string]string ``` -Instead, you can initialize an empty map like we were doing above, or use the `make` keyword to create a map for you: +Ao invés disso, você pode inicializar um map vazio como fizemos lá em cima, ou usando a palavra-chave `make` para criar um map para você:` keyword to create a map for you: ```go -dictionary = map[string]string{} +dicionario = map[string]string{} -// OR +// OU -dictionary = make(map[string]string) +dicionario = make(map[string]string) ``` -Both approaches create an empty `hash map` and point `dictionary` at it. Which ensures that you will never get a runtime panic. +Ambas as abordagens criam um `hash map` vazio e apontam um `dicionario` para ele. Assim, nos certificamos que você nunca vai obter um panic em tempo de execução. -## Refactor +## Refatoração -There isn't much to refactor in our implementation but the test could use a little simplification. +Não há muito para refatorar na nossa implementação, mas podemos simplificar o teste um pouco. ```go -func TestAdd(t *testing.T) { - dictionary := Dictionary{} - word := "test" - definition := "this is just a test" +func TestAdiciona(t *testing.T) { + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" - dictionary.Add(word, definition) + dicionario.Adiciona(palavra, definicao) - assertDefinition(t, dictionary, word, definition) + comparaDefinicao(t, dicionario, palavra, definicao) } -func assertDefinition(t *testing.T, dictionary Dictionary, word, definition string) { - t.Helper() +func comparaDefinicao(t *testing.T, dicionario Dicionario, palavra, definicao string) { + t.Helper() - got, err := dictionary.Search(word) - if err != nil { - t.Fatal("should find added word:", err) - } + resultado, err := dicionario.Busca(palavra) + if err != nil { + t.Fatal("deveria ter encontrado palavra adicionada:", err) + } - if definition != got { - t.Errorf("got '%s' want '%s'", got, definition) - } + if definicao != resultado { + t.Errorf("resultado '%s', esperado '%s'", resultado, definicao) + } } ``` -We made variables for word and definition, and moved the definition assertion into its own helper function. +Criamos variáveis para palavra e definição e movemos a comparação da definição para sua própria função auxiliar. -Our `Add` is looking good. Except, we didn't consider what happens when the value we are trying to add already exists! +Nosso `Adiciona` está bom. No entanto, não consideramos o que acontece quando o valor que estamos tentando adicionar já existe! -Map will not throw an error if the value already exists. Instead, they will go ahead and overwrite the value with the newly provided value. This can be convenient in practice, but makes our function name less than accurate. `Add` should not modify existing values. It should only add new words to our dictionary. +O map não vai mostrar um erro se o valor já existe. Ao invés disso, elas vão sobrescrever o valor com o novo recebido. Isso pode ser conveniente na prática, mas torna o nome da nossa função muito menos preciso. `Adiciona` não deve modificar valores existentes. Só deve adicionar palavras novas ao nosso dicionário. ## Write the test first From 5c55340d13aa5062ae9bbc93d8a1576713a753f2 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Tue, 30 Jul 2019 20:52:34 -0300 Subject: [PATCH 04/10] =?UTF-8?q?Tradu=C3=A7=C3=A3o=20da=20fun=C3=A7=C3=A3?= =?UTF-8?q?o=20Adiciona?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maps/v3/dicionario_test.go | 2 +- maps/v4/dicionario.go | 45 ++++++++++++ maps/v4/dicionario_test.go | 74 +++++++++++++++++++ maps/v4/dictionary.go | 45 ------------ maps/v4/dictionary_test.go | 74 ------------------- primeiros-passos-com-go/maps.md | 126 ++++++++++++++++---------------- 6 files changed, 185 insertions(+), 181 deletions(-) create mode 100644 maps/v4/dicionario.go create mode 100644 maps/v4/dicionario_test.go delete mode 100644 maps/v4/dictionary.go delete mode 100644 maps/v4/dictionary_test.go diff --git a/maps/v3/dicionario_test.go b/maps/v3/dicionario_test.go index f1341921..9079ac78 100644 --- a/maps/v3/dicionario_test.go +++ b/maps/v3/dicionario_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -func TestSearch(t *testing.T) { +func TestBusca(t *testing.T) { dicionario := Dicionario{"teste": "isso é apenas um teste"} t.Run("palavra conhecida", func(t *testing.T) { diff --git a/maps/v4/dicionario.go b/maps/v4/dicionario.go new file mode 100644 index 00000000..c54002af --- /dev/null +++ b/maps/v4/dicionario.go @@ -0,0 +1,45 @@ +package main + +const ( + // ErrNaoEncontrado significa que a definição não pôde ser encontrada para determinada palavra + ErrNaoEncontrado = ErrDicionario("não foi possível encontrar a palavra que você procura") + + // ErrPalavraExistente significa que você está tentando adicionar uma palavra que já existe + ErrPalavraExistente = ErrDicionario("não é possível adicionar a palavra pois ela já existe") +) + +// ErrDicionario são erros que podem acontecer quando se interage com o dicionário +type ErrDicionario string + +func (e ErrDicionario) Error() string { + return string(e) +} + +// Dicionario armazena definições de palavras +type Dicionario map[string]string + +// Busca encontra uma palavra no dicionário +func (d Dicionario) Busca(palavra string) (string, error) { + definicao, existe := d[palavra] + if !existe { + return "", ErrNaoEncontrado + } + + return definicao, nil +} + +// Adiciona insere uma palavra e definição no dicionário +func (d Dicionario) Adiciona(palavra, definicao string) error { + _, err := d.Busca(palavra) + switch err { + case ErrNaoEncontrado: + d[palavra] = definicao + case nil: + return ErrPalavraExistente + default: + return err + + } + + return nil +} diff --git a/maps/v4/dicionario_test.go b/maps/v4/dicionario_test.go new file mode 100644 index 00000000..a45f524f --- /dev/null +++ b/maps/v4/dicionario_test.go @@ -0,0 +1,74 @@ +package main + +import ( + "testing" +) + +func TestBusca(t *testing.T) { + dicionario := Dicionario{"teste": "isso é apenas um teste"} + + t.Run("palavra conhecida", func(t *testing.T) { + resultado, _ := dicionario.Busca("teste") + esperado := "isso é apenas um teste" + + comparaStrings(t, resultado, esperado) + }) + + t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") + + comparaErro(t, resultado, ErrNaoEncontrado) + }) +} + +func TestAdiciona(t *testing.T) { + t.Run("palavra nova", func(t *testing.T) { + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" + + err := dicionario.Adiciona(palavra, definicao) + + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, definicao) + }) + + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Add(palavra, "teste novo") + + comparaErro(t, err, ErrPalavraExistente) + comparaDefinicao(t, dicionario, palavra, definicao) + }) +} + +func comparaStrings(t *testing.T, resultado, esperado string) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaErro(t *testing.T, resultado, esperado error) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado erro '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaDefinicao(t *testing.T, dicionario Dicionario, palavra, definicao string) { + t.Helper() + + resultado, err := dicionario.Busca(palavra) + if err != nil { + t.Fatal("deveria ter encontrado palavra adicionada:", err) + } + + if definicao != resultado { + t.Errorf("resultado '%s', esperado '%s'", resultado, definicao) + } +} diff --git a/maps/v4/dictionary.go b/maps/v4/dictionary.go deleted file mode 100644 index f59197e2..00000000 --- a/maps/v4/dictionary.go +++ /dev/null @@ -1,45 +0,0 @@ -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") -) - -// DictionaryErr are errors that can happen when interacting with the dictionary -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 -} diff --git a/maps/v4/dictionary_test.go b/maps/v4/dictionary_test.go deleted file mode 100644 index 1eac2ea8..00000000 --- a/maps/v4/dictionary_test.go +++ /dev/null @@ -1,74 +0,0 @@ -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 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) - } -} diff --git a/primeiros-passos-com-go/maps.md b/primeiros-passos-com-go/maps.md index 82cb7a82..8066b74f 100644 --- a/primeiros-passos-com-go/maps.md +++ b/primeiros-passos-com-go/maps.md @@ -339,110 +339,114 @@ Nosso `Adiciona` está bom. No entanto, não consideramos o que acontece quando O map não vai mostrar um erro se o valor já existe. Ao invés disso, elas vão sobrescrever o valor com o novo recebido. Isso pode ser conveniente na prática, mas torna o nome da nossa função muito menos preciso. `Adiciona` não deve modificar valores existentes. Só deve adicionar palavras novas ao nosso dicionário. -## Write the test first +## Escreva o teste primeiro ```go -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 TestAdiciona(t *testing.T) { + t.Run("palavra nova", func(t *testing.T) { + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" + + err := dicionario.Adiciona(palavra, definicao) + + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, definicao) + }) + + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Add(palavra, "teste novo") + + comparaErro(t, err, ErrPalavraExistente) + comparaDefinicao(t, dicionario, palavra, definicao) + }) } ``` -For this test, we modified `Add` to return an error, which we are validating against a new error variable, `ErrWordExists`. We also modified the previous test to check for a `nil` error. +Para esse teste, fizemos `Adiciona` devolver um erro, que estamos validando com uma nova variável de erro, `ErrPalavraExistente`. Também modificamos o teste anterior para verificar um erro `nil`. -## Try to run test +## Execute o teste -The compiler will fail because we are not returning a value for `Add`. +Agora o compilador vai falhar porque não estamos devolvendo um valor para `Adiciona`. -```text -./dictionary_test.go:30:13: dictionary.Add(word, definition) used as value -./dictionary_test.go:41:13: dictionary.Add(word, "new test") used as value +```bash +./dicionario_test.go:30:13: dicionario.Adiciona(palavra, definicao) used as value +./dicionario_test.go:41:13: dicionario.Adiciona(palavra, "teste novo") used as value ``` -## Write the minimal amount of code for the test to run and check the output +`usado como valor` + +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste falhado -In `dictionary.go` +Em `dicionario.go` ```go var ( - ErrNotFound = errors.New("could not find the word you were looking for") - ErrWordExists = errors.New("cannot add word because it already exists") + ErrNaoEncontrado = errors.New("não foi possível encontrar a palavra que você procura") + ErrPalavraExistente = errors.New("não é possível adicionar a palavra pois ela já existe") ) -func (d Dictionary) Add(word, definition string) error { - d[word] = definition +func (d Dicionario) Adiciona(palavra, definicao string) error { + d[palavra] = definicao return nil } ``` +Agora temos mais dois erros. Ainda estamos modificando o valor e retornando um erro `nil`. + Now we get two more errors. We are still modifying the value, and returning a `nil` error. -```text -dictionary_test.go:43: got error '%!s()' want 'cannot add word because it already exists' -dictionary_test.go:44: got 'new test' want 'this is just a test' +```bash +dicionario_test.go:43: resultado erro '%!s()', esperado 'não é possível adicionar a palavra pois ela já existe' +dicionario_test.go:44: resultado 'teste novo', esperado 'isso é apenas um teste' ``` -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar ```go -func (d Dictionary) Add(word, definition string) error { - _, err := d.Search(word) - +func (d Dicionario) Adiciona(palavra, definicao string) error { + _, err := d.Busca(palavra) switch err { - case ErrNotFound: - d[word] = definition + case ErrNaoEncontrado: + d[palavra] = definicao case nil: - return ErrWordExists + return ErrPalavraExistente default: return err + } return nil } ``` -Here we are using a `switch` statement to match on the error. Having a `switch` like this provides an extra safety net, in case `Search` returns an error other than `ErrNotFound`. +Aqui estamos usando a declaração `switch` para coincidir com o erro. Usar o `switch` dessa forma dá uma segurança a mais, no caso de `Busca` retornar um erro diferente de `ErrNaoEncontrado`. -## Refactor +## Refatoração -We don't have too much to refactor, but as our error usage grows we can make a few modifications. +Não temos muito o que refatorar, mas já que nossos erros estão aumentando, podemos fazer algumas modificações. ```go const ( - ErrNotFound = DictionaryErr("could not find the word you were looking for") - ErrWordExists = DictionaryErr("cannot add word because it already exists") + ErrNaoEncontrado = ErrDicionario("não foi possível encontrar a palavra que você procura") + ErrPalavraExistente = ErrDicionario("não é possível adicionar a palavra pois ela já existe") ) -type DictionaryErr string +type ErrDicionario string -func (e DictionaryErr) Error() string { +func (e ErrDicionario) Error() string { return string(e) } ``` -We made the errors constant; this required us to create our own `DictionaryErr` type which implements the `error` interface. You can read more about the details in [this excellent article by Dave Cheney](https://dave.cheney.net/2016/04/07/constant-errors). Simply put, it makes the errors more reusable and immutable. +Tornamos os erros constantes; para isso, tivemos que criar nosso próprio tipo `ErrDicionario` que implementa a interface `error`. Você pode ler mais sobre nesse [artigo excelente escrito por Dave Cheney](https://dave.cheney.net/2016/04/07/constant-errors) (em inglês). Resumindo, isso torna os erros mais reutilizáveis e imutáveis. -Next, let's create a function to `Update` the definition of a word. +Agora, vamos criar uma função que `Atualiza` a definição de uma palavra. -## Write the test first +## Escreva o teste primeiro ```go func TestUpdate(t *testing.T) { @@ -459,7 +463,7 @@ func TestUpdate(t *testing.T) { `Update` is very closely related to `Add` and will be our next implementation. -## Try and run the test +## Execute o teste ```text ./dictionary_test.go:53:2: dictionary.Update undefined (type Dictionary has no field or method Update) @@ -479,7 +483,7 @@ With that in place, we are able to see that we need to change the definition of dictionary_test.go:55: got 'this is just a test' want 'new definition' ``` -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar We already saw how to do this when we fixed the issue with `Add`. So let's implement something really similar to `Add`. @@ -491,7 +495,7 @@ func (d Dictionary) Update(word, definition string) { There is no refactoring we need to do on this since it was a simple change. However, we now have the same issue as with `Add`. If we pass in a new word, `Update` will add it to the dictionary. -## Write the test first +## Escreva o teste primeiro ```go t.Run("existing word", func(t *testing.T) { @@ -519,7 +523,7 @@ t.Run("new word", func(t *testing.T) { We added yet another error type for when the word does not exist. We also modified `Update` to return an `error` value. -## Try and run the test +## Execute o teste ```text ./dictionary_test.go:53:16: dictionary.Update(word, "new test") used as value @@ -552,7 +556,7 @@ With these changes, we now get a very clear error: dictionary_test.go:66: got error '%!s()' want 'cannot update word because it does not exist' ``` -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar ```go func (d Dictionary) Update(word, definition string) error { @@ -583,7 +587,7 @@ Having specific errors gives you more information about what went wrong. Here is Next, let's create a function to `Delete` a word in the dictionary. -## Write the test first +## Escreva o teste primeiro ```go func TestDelete(t *testing.T) { @@ -623,7 +627,7 @@ After we add this, the test tells us we are not deleting the word. dictionary_test.go:78: Expected 'test' to be deleted ``` -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar ```go func (d Dictionary) Delete(word string) { From 62869a6a00ddfe082c8adcdcf9ae7de05b1fe974 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Tue, 30 Jul 2019 20:52:44 -0300 Subject: [PATCH 05/10] =?UTF-8?q?Padroniza=C3=A7=C3=A3o=20de=20exemplo.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meta/exemplo.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/meta/exemplo.md b/meta/exemplo.md index bae8ece7..4df2f0f5 100644 --- a/meta/exemplo.md +++ b/meta/exemplo.md @@ -2,15 +2,15 @@ Introdução -## Escrever o teste primeiro +## Escreva o teste primeiro -## Tentar executar o teste +## Execute o teste -## Escrever o mínimo possível para fazer o teste rodar e verificar a saída do teste que houver falha +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado -## Escrever código o suficente para fazê-lo passar +## Escreva código o suficiente para fazer o teste passar -## Refatorar +## Refatoração ## Repetir a cada novo requerimento From 7b140ca09fbb1091adbcd3e7b6702aae8a82699b Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Tue, 30 Jul 2019 21:28:57 -0300 Subject: [PATCH 06/10] =?UTF-8?q?Tradu=C3=A7=C3=A3o=20da=20fun=C3=A7=C3=A3?= =?UTF-8?q?o=20Atualiza?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maps/v4/dicionario_test.go | 2 +- maps/v5/dicionario.go | 50 ++++++++++++ maps/v5/dicionario_test.go | 85 +++++++++++++++++++ maps/v5/dictionary.go | 50 ------------ maps/v5/dictionary_test.go | 85 ------------------- maps/v6/dicionario.go | 64 +++++++++++++++ maps/v6/dicionario_test.go | 97 ++++++++++++++++++++++ maps/v6/dictionary.go | 64 --------------- maps/v6/dictionary_test.go | 97 ---------------------- primeiros-passos-com-go/maps.md | 139 ++++++++++++++++---------------- 10 files changed, 368 insertions(+), 365 deletions(-) create mode 100644 maps/v5/dicionario.go create mode 100644 maps/v5/dicionario_test.go delete mode 100644 maps/v5/dictionary.go delete mode 100644 maps/v5/dictionary_test.go create mode 100644 maps/v6/dicionario.go create mode 100644 maps/v6/dicionario_test.go delete mode 100644 maps/v6/dictionary.go delete mode 100644 maps/v6/dictionary_test.go diff --git a/maps/v4/dicionario_test.go b/maps/v4/dicionario_test.go index a45f524f..189b1439 100644 --- a/maps/v4/dicionario_test.go +++ b/maps/v4/dicionario_test.go @@ -37,7 +37,7 @@ func TestAdiciona(t *testing.T) { palavra := "teste" definicao := "isso é apenas um teste" dicionario := Dicionario{palavra: definicao} - err := dicionario.Add(palavra, "teste novo") + err := dicionario.Adiciona(palavra, "teste novo") comparaErro(t, err, ErrPalavraExistente) comparaDefinicao(t, dicionario, palavra, definicao) diff --git a/maps/v5/dicionario.go b/maps/v5/dicionario.go new file mode 100644 index 00000000..264c497a --- /dev/null +++ b/maps/v5/dicionario.go @@ -0,0 +1,50 @@ +package main + +const ( + // ErrNaoEncontrado significa que a definição não pôde ser encontrada para determinada palavra + ErrNaoEncontrado = ErrDicionario("não foi possível encontrar a palavra que você procura") + + // ErrPalavraExistente significa que você está tentando adicionar uma palavra que já existe + ErrPalavraExistente = ErrDicionario("não é possível adicionar a palavra pois ela já existe") +) + +// ErrDicionario são erros que podem acontecer quando se interage com o dicionário +type ErrDicionario string + +func (e ErrDicionario) Error() string { + return string(e) +} + +// Dicionario armazena definições de palavras +type Dicionario map[string]string + +// Busca encontra uma palavra no dicionário +func (d Dicionario) Busca(palavra string) (string, error) { + definicao, existe := d[palavra] + if !existe { + return "", ErrNaoEncontrado + } + + return definicao, nil +} + +// Adiciona insere uma palavra e definição no dicionário +func (d Dicionario) Adiciona(palavra, definicao string) error { + _, err := d.Busca(palavra) + switch err { + case ErrNaoEncontrado: + d[palavra] = definicao + case nil: + return ErrPalavraExistente + default: + return err + + } + + return nil +} + +// Atualiza muda a definição de determinada palavra +func (d Dicionario) Atualiza(palavra, definicao string) { + d[palavra] = definicao +} diff --git a/maps/v5/dicionario_test.go b/maps/v5/dicionario_test.go new file mode 100644 index 00000000..1fa49657 --- /dev/null +++ b/maps/v5/dicionario_test.go @@ -0,0 +1,85 @@ +package main + +import ( + "testing" +) + +func TestBusca(t *testing.T) { + dicionario := Dicionario{"teste": "isso é apenas um teste"} + + t.Run("palavra conhecida", func(t *testing.T) { + resultado, _ := dicionario.Busca("teste") + esperado := "isso é apenas um teste" + + comparaStrings(t, resultado, esperado) + }) + + t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") + + comparaErro(t, resultado, ErrNaoEncontrado) + }) +} + +func TestAdiciona(t *testing.T) { + t.Run("palavra nova", func(t *testing.T) { + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" + + err := dicionario.Adiciona(palavra, definicao) + + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, definicao) + }) + + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Adiciona(palavra, "teste novo") + + comparaErro(t, err, ErrPalavraExistente) + comparaDefinicao(t, dicionario, palavra, definicao) + }) +} + +func TestAtualiza(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + novaDefinicao := "nova definição" + + dicionario.Atualiza(palavra, novaDefinicao) + + comparaDefinicao(t, dicionario, palavra, novaDefinicao) +} + +func comparaStrings(t *testing.T, resultado, esperado string) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaErro(t *testing.T, resultado, esperado error) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado erro '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaDefinicao(t *testing.T, dicionario Dicionario, palavra, definicao string) { + t.Helper() + + resultado, err := dicionario.Busca(palavra) + if err != nil { + t.Fatal("deveria ter encontrado palavra adicionada:", err) + } + + if definicao != resultado { + t.Errorf("resultado '%s', esperado '%s'", resultado, definicao) + } +} diff --git a/maps/v5/dictionary.go b/maps/v5/dictionary.go deleted file mode 100644 index 8f8e98d5..00000000 --- a/maps/v5/dictionary.go +++ /dev/null @@ -1,50 +0,0 @@ -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") -) - -// DictionaryErr are errors that can happen when interacting with the dictionary -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) { - d[word] = definition -} diff --git a/maps/v5/dictionary_test.go b/maps/v5/dictionary_test.go deleted file mode 100644 index 0d6d2c61..00000000 --- a/maps/v5/dictionary_test.go +++ /dev/null @@ -1,85 +0,0 @@ -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) { - word := "test" - definition := "this is just a test" - dictionary := Dictionary{word: definition} - newDefinition := "new definition" - - dictionary.Update(word, newDefinition) - - assertDefinition(t, dictionary, word, newDefinition) -} - -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) - } -} diff --git a/maps/v6/dicionario.go b/maps/v6/dicionario.go new file mode 100644 index 00000000..166583ab --- /dev/null +++ b/maps/v6/dicionario.go @@ -0,0 +1,64 @@ +package main + +const ( + // ErrNaoEncontrado significa que a definição não pôde ser encontrada para determinada palavra + ErrNaoEncontrado = ErrDicionario("não foi possível encontrar a palavra que você procura") + + // ErrPalavraExistente significa que você está tentando adicionar uma palavra que já existe + ErrPalavraExistente = ErrDicionario("não é possível adicionar a palavra pois ela já existe") + + // ErrPalavraInexistente ocorre quando há tentativa de atualização de uma palavra que não está no dicionário + ErrPalavraInexistente = ErrDicionario("não foi possível atualizar a palavra pois ela não existe") +) + +// ErrDicionario são erros que podem acontecer quando se interage com o dicionário +type ErrDicionario string + +func (e ErrDicionario) Error() string { + return string(e) +} + +// Dicionario armazena definições de palavras +type Dicionario map[string]string + +// Busca encontra uma palavra no dicionário +func (d Dicionario) Busca(palavra string) (string, error) { + definicao, existe := d[palavra] + if !existe { + return "", ErrNaoEncontrado + } + + return definicao, nil +} + +// Adiciona insere uma palavra e definição no dicionário +func (d Dicionario) Adiciona(palavra, definicao string) error { + _, err := d.Busca(palavra) + switch err { + case ErrNaoEncontrado: + d[palavra] = definicao + case nil: + return ErrPalavraExistente + default: + return err + + } + + return nil +} + +// Atualiza muda a definição de determinada palavra +func (d Dicionario) Atualiza(palavra, definicao string) error { + _, err := d.Busca(palavra) + switch err { + case ErrNaoEncontrado: + return ErrPalavraInexistente + case nil: + d[palavra] = definicao + default: + return err + + } + + return nil +} diff --git a/maps/v6/dicionario_test.go b/maps/v6/dicionario_test.go new file mode 100644 index 00000000..b8ca2e7f --- /dev/null +++ b/maps/v6/dicionario_test.go @@ -0,0 +1,97 @@ +package main + +import ( + "testing" +) + +func TestBusca(t *testing.T) { + dicionario := Dicionario{"teste": "isso é apenas um teste"} + + t.Run("palavra conhecida", func(t *testing.T) { + resultado, _ := dicionario.Busca("teste") + esperado := "isso é apenas um teste" + + comparaStrings(t, resultado, esperado) + }) + + t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") + + comparaErro(t, resultado, ErrNaoEncontrado) + }) +} + +func TestAdiciona(t *testing.T) { + t.Run("palavra nova", func(t *testing.T) { + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" + + err := dicionario.Adiciona(palavra, definicao) + + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, definicao) + }) + + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Adiciona(palavra, "teste novo") + + comparaErro(t, err, ErrPalavraExistente) + comparaDefinicao(t, dicionario, palavra, definicao) + }) +} + +func TestAtualiza(t *testing.T) { + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + novaDefinicao := "nova definição" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Atualiza(palavra, novaDefinicao) + + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, novaDefinicao) + }) + + t.Run("palavra nova", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{} + + err := dicionario.Atualiza(palavra, definicao) + + comparaErro(t, err, ErrPalavraInexistente) + }) +} + +func comparaStrings(t *testing.T, resultado, esperado string) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaErro(t *testing.T, resultado, esperado error) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado erro '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaDefinicao(t *testing.T, dicionario Dicionario, palavra, definicao string) { + t.Helper() + + resultado, err := dicionario.Busca(palavra) + if err != nil { + t.Fatal("deveria ter encontrado palavra adicionada:", err) + } + + if definicao != resultado { + t.Errorf("resultado '%s', esperado '%s'", resultado, definicao) + } +} diff --git a/maps/v6/dictionary.go b/maps/v6/dictionary.go deleted file mode 100644 index 22059a8c..00000000 --- a/maps/v6/dictionary.go +++ /dev/null @@ -1,64 +0,0 @@ -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") -) - -// DictionaryErr are errors that can happen when interacting with the dictionary -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 -} diff --git a/maps/v6/dictionary_test.go b/maps/v6/dictionary_test.go deleted file mode 100644 index 7fed60e9..00000000 --- a/maps/v6/dictionary_test.go +++ /dev/null @@ -1,97 +0,0 @@ -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 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) - } -} diff --git a/primeiros-passos-com-go/maps.md b/primeiros-passos-com-go/maps.md index 8066b74f..df00e682 100644 --- a/primeiros-passos-com-go/maps.md +++ b/primeiros-passos-com-go/maps.md @@ -450,142 +450,145 @@ Agora, vamos criar uma função que `Atualiza` a definição de uma palavra. ```go func TestUpdate(t *testing.T) { - word := "test" - definition := "this is just a test" - dictionary := Dictionary{word: definition} - newDefinition := "new definition" + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + novaDefinicao := "nova definição" - dictionary.Update(word, newDefinition) + dicionario.Atualiza(palavra, novaDefinicao) - assertDefinition(t, dictionary, word, newDefinition) + comparaDefinicao(t, dicionario, palavra, novaDefinicao) } ``` -`Update` is very closely related to `Add` and will be our next implementation. +`Atualiza` é bem parecido com `Adiciona` e será nossa próxima implementação. ## Execute o teste -```text -./dictionary_test.go:53:2: dictionary.Update undefined (type Dictionary has no field or method Update) +```bash +./dicionario_test.go:53:2: dicionario.Atualiza undefined (type Dicionario has no field or method Atualiza) ``` -## Write minimal amount of code for the test to run and check the failing test output +`dicionario.Atualiza não definido (tipo Dicionario não tem nenhum campo ou método chamado Atualiza` + +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado -We already know how to deal with an error like this. We need to define our function. +Já sabemos como lidar com um erro como esse. Precisamos definir nossa função. ```go -func (d Dictionary) Update(word, definition string) {} +func (d Dicionario) Atualiza(palavra, definicao string) {} ``` +Feito isso, somos capazes de ver o que precisamos para mudar a definição da palavra. + With that in place, we are able to see that we need to change the definition of the word. -```text -dictionary_test.go:55: got 'this is just a test' want 'new definition' +```bash +dicionario_test.go:55: resultado 'isso é apenas um teste', esperado 'nova definição' ``` ## Escreva código o suficiente para fazer o teste passar -We already saw how to do this when we fixed the issue with `Add`. So let's implement something really similar to `Add`. +Já vimos como fazer essa implementação quando corrigimos o problema com `Adiciona`. Logo, vamos implementar algo bem parecido a `Adiciona`. ```go -func (d Dictionary) Update(word, definition string) { - d[word] = definition +func (d Dicionario) Atualiza(palavra, definicao string) { + d[palavra] = definicao } ``` -There is no refactoring we need to do on this since it was a simple change. However, we now have the same issue as with `Add`. If we pass in a new word, `Update` will add it to the dictionary. +Não há refatoração necessária, já que foi uma mudança simples. No entanto, agora temos o mesmo problema com `Adiciona`. Se passarmos uma palavra nova, `Atualiza` vai adicioná-la no dicionário. ## Escreva o teste primeiro ```go -t.Run("existing word", func(t *testing.T) { - word := "test" - definition := "this is just a test" - newDefinition := "new definition" - dictionary := Dictionary{word: definition} + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + novaDefinicao := "nova definição" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Atualiza(palavra, novaDefinicao) - err := dictionary.Update(word, newDefinition) + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, novaDefinicao) + }) - assertError(t, err, nil) - assertDefinition(t, dictionary, word, newDefinition) -}) + t.Run("palavra nova", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{} -t.Run("new word", func(t *testing.T) { - word := "test" - definition := "this is just a test" - dictionary := Dictionary{} - - err := dictionary.Update(word, definition) + err := dicionario.Atualiza(palavra, definicao) - assertError(t, err, ErrWordDoesNotExist) -}) + comparaErro(t, err, ErrPalavraInexistente) + }) ``` -We added yet another error type for when the word does not exist. We also modified `Update` to return an `error` value. +Criamos um outro tipo de erro para quando a palavra não existe. Também modificamos o `Atualiza` para retornar um valor `error`. ## Execute o teste -```text -./dictionary_test.go:53:16: dictionary.Update(word, "new test") used as value -./dictionary_test.go:64:16: dictionary.Update(word, definition) used as value -./dictionary_test.go:66:23: undefined: ErrWordDoesNotExists +```bash +./dicionario_test.go:53:16: dicionario.Atualiza(palavra, "teste novo") used as value +./dicionario_test.go:64:16: dicionario.Atualiza(palavra, definicao) used as value +./dicionario_test.go:66:23: undefined: ErrPalavraInexistente ``` -We get 3 errors this time, but we know how to deal with these. +Agora recebemos três erros, mas sabemos como lidar com eles. -## Write the minimal amount of code for the test to run and check the failing test output +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado ```go const ( - ErrNotFound = DictionaryErr("could not find the word you were looking for") - ErrWordExists = DictionaryErr("cannot add word because it already exists") - ErrWordDoesNotExist = DictionaryErr("cannot update word because it does not exist") + ErrNaoEncontrado = ErrDicionario("não foi possível encontrar a palavra que você procura") + ErrPalavraExistente = ErrDicionario("não é possível adicionar a palavra pois ela já existe") + ErrPalavraInexistente = ErrDicionario("não foi possível atualizar a palavra pois ela não existe") ) -func (d Dictionary) Update(word, definition string) error { - d[word] = definition +func (d Dicionario) Atualiza(palavra, definicao string) error { + d[palavra] = definicao return nil } ``` -We added our own error type and are returning a `nil` error. +Adicionamos nosso próprio tipo erro e retornamos um erro `nil`. -With these changes, we now get a very clear error: +Com essas mudanças, agora temos um erro muito mais claro: -```text -dictionary_test.go:66: got error '%!s()' want 'cannot update word because it does not exist' +```bash +dicionario_test.go:66: resultado erro '%!s()', esperado 'não foi possível atualizar a palavra pois ela não existe' ``` ## Escreva código o suficiente para fazer o teste passar ```go -func (d Dictionary) Update(word, definition string) error { - _, err := d.Search(word) +func (d Dicionario) Atualiza(palavra, definicao string) error { + _, err := d.Busca(palavra) + switch err { + case ErrNaoEncontrado: + return ErrPalavraInexistente + case nil: + d[palavra] = definicao + default: + return err - switch err { - case ErrNotFound: - return ErrWordDoesNotExist - case nil: - d[word] = definition - default: - return err - } + } - return nil + return nil } ``` -This function looks almost identical to `Add` except we switched when we update the `dictionary` and when we return an error. +Essa função é quase idêntica à `Adiciona`, com exceção de que trocamos quando atualizamos o `dicionario` e quando retornamos um erro. -### Note on declaring a new error for Update +### Nota sobre a declaração de um novo erro para Atualiza -We could reuse `ErrNotFound` and not add a new error. However, it is often better to have a precise error for when an update fails. +Poderíamos reutilizar `ErrNaoEncontrado` e não criar um novo erro. No entanto, geralmente é melhor ter um erro preciso para quando uma atualização falhar. -Having specific errors gives you more information about what went wrong. Here is an example in a web app: +Ter erros específicos te dá mais informação sobre o que deu errado. Segue um exemplo em uma aplicação web: -> You can redirect the user when `ErrNotFound` is encountered, but display an error message when `ErrWordDoesNotExist` is encountered. +> Você pode redirecionar o usuário quando o `ErrNaoEncontrado` é encontrado, mas mostrar uma mensagem de erro só quando `ErrPalavraInexistente` é encontrado. -Next, let's create a function to `Delete` a word in the dictionary. +Agora, vamos criar uma função que `Deleta` uma palavra no dicionário. ## Escreva o teste primeiro From b1f93ceccfc7c32b7e7e735dc29e1dc7ba52f987 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Tue, 30 Jul 2019 21:46:02 -0300 Subject: [PATCH 07/10] =?UTF-8?q?Finaliza=C3=A7=C3=A3o=20da=20tradu=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20maps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maps/v7/dicionario.go | 69 ++++++++++++++++++++ maps/v7/dicionario_test.go | 109 ++++++++++++++++++++++++++++++++ maps/v7/dictionary.go | 69 -------------------- maps/v7/dictionary_test.go | 109 -------------------------------- primeiros-passos-com-go/maps.md | 64 ++++++++++--------- 5 files changed, 211 insertions(+), 209 deletions(-) create mode 100644 maps/v7/dicionario.go create mode 100644 maps/v7/dicionario_test.go delete mode 100644 maps/v7/dictionary.go delete mode 100644 maps/v7/dictionary_test.go diff --git a/maps/v7/dicionario.go b/maps/v7/dicionario.go new file mode 100644 index 00000000..0312cf92 --- /dev/null +++ b/maps/v7/dicionario.go @@ -0,0 +1,69 @@ +package main + +const ( + // ErrNaoEncontrado significa que a definição não pôde ser encontrada para determinada palavra + ErrNaoEncontrado = ErrDicionario("não foi possível encontrar a palavra que você procura") + + // ErrPalavraExistente significa que você está tentando adicionar uma palavra que já existe + ErrPalavraExistente = ErrDicionario("não é possível adicionar a palavra pois ela já existe") + + // ErrPalavraInexistente ocorre quando há tentativa de atualização de uma palavra que não está no dicionário + ErrPalavraInexistente = ErrDicionario("não foi possível atualizar a palavra pois ela não existe") +) + +// ErrDicionario são erros que podem acontecer quando se interage com o dicionário +type ErrDicionario string + +func (e ErrDicionario) Error() string { + return string(e) +} + +// Dicionario armazena definições de palavras +type Dicionario map[string]string + +// Busca encontra uma palavra no dicionário +func (d Dicionario) Busca(palavra string) (string, error) { + definicao, existe := d[palavra] + if !existe { + return "", ErrNaoEncontrado + } + + return definicao, nil +} + +// Adiciona insere uma palavra e definição no dicionário +func (d Dicionario) Adiciona(palavra, definicao string) error { + _, err := d.Busca(palavra) + switch err { + case ErrNaoEncontrado: + d[palavra] = definicao + case nil: + return ErrPalavraExistente + default: + return err + + } + + return nil +} + +// Atualiza muda a definição de determinada palavra +func (d Dicionario) Atualiza(palavra, definicao string) error { + _, err := d.Busca(palavra) + switch err { + case ErrNaoEncontrado: + return ErrPalavraInexistente + case nil: + d[palavra] = definicao + default: + return err + + } + + return nil +} + +// Deleta remove uma palavra do dicionário +func (d Dicionario) Deleta(palavra string) { + delete(d, palavra) +} diff --git a/maps/v7/dicionario_test.go b/maps/v7/dicionario_test.go new file mode 100644 index 00000000..9a42b503 --- /dev/null +++ b/maps/v7/dicionario_test.go @@ -0,0 +1,109 @@ +package main + +import ( + "testing" +) + +func TestBusca(t *testing.T) { + dicionario := Dicionario{"teste": "isso é apenas um teste"} + + t.Run("palavra conhecida", func(t *testing.T) { + resultado, _ := dicionario.Busca("teste") + esperado := "isso é apenas um teste" + + comparaStrings(t, resultado, esperado) + }) + + t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") + + comparaErro(t, resultado, ErrNaoEncontrado) + }) +} + +func TestAdiciona(t *testing.T) { + t.Run("palavra nova", func(t *testing.T) { + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" + + err := dicionario.Adiciona(palavra, definicao) + + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, definicao) + }) + + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Adiciona(palavra, "teste novo") + + comparaErro(t, err, ErrPalavraExistente) + comparaDefinicao(t, dicionario, palavra, definicao) + }) +} + +func TestAtualiza(t *testing.T) { + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + novaDefinicao := "nova definição" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Atualiza(palavra, novaDefinicao) + + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, novaDefinicao) + }) + + t.Run("palavra nova", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{} + + err := dicionario.Atualiza(palavra, definicao) + + comparaErro(t, err, ErrPalavraInexistente) + }) +} + +func TestDeleta(t *testing.T) { + palavra := "teste" + dicionario := Dicionario{palavra: "definição de teste"} + + dicionario.Deleta(palavra) + + _, err := dicionario.Busca(palavra) + if err != ErrNaoEncontrado { + t.Errorf("espera-se que '%s' seja deletado", palavra) + } +} + +func comparaStrings(t *testing.T, resultado, esperado string) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaErro(t *testing.T, resultado, esperado error) { + t.Helper() + + if resultado != esperado { + t.Errorf("resultado erro '%s', esperado '%s'", resultado, esperado) + } +} + +func comparaDefinicao(t *testing.T, dicionario Dicionario, palavra, definicao string) { + t.Helper() + + resultado, err := dicionario.Busca(palavra) + if err != nil { + t.Fatal("deveria ter encontrado palavra adicionada:", err) + } + + if definicao != resultado { + t.Errorf("resultado '%s', esperado '%s'", resultado, definicao) + } +} diff --git a/maps/v7/dictionary.go b/maps/v7/dictionary.go deleted file mode 100644 index e54f3e63..00000000 --- a/maps/v7/dictionary.go +++ /dev/null @@ -1,69 +0,0 @@ -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") -) - -// DictionaryErr are errors that can happen when interacting with the dictionary -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) -} diff --git a/maps/v7/dictionary_test.go b/maps/v7/dictionary_test.go deleted file mode 100644 index a08af18c..00000000 --- a/maps/v7/dictionary_test.go +++ /dev/null @@ -1,109 +0,0 @@ -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) - } -} diff --git a/primeiros-passos-com-go/maps.md b/primeiros-passos-com-go/maps.md index df00e682..9457fa82 100644 --- a/primeiros-passos-com-go/maps.md +++ b/primeiros-passos-com-go/maps.md @@ -593,64 +593,66 @@ Agora, vamos criar uma função que `Deleta` uma palavra no dicionário. ## Escreva o teste primeiro ```go -func TestDelete(t *testing.T) { - word := "test" - dictionary := Dictionary{word: "test definition"} +func TestDeleta(t *testing.T) { + palavra := "teste" + dicionario := Dicionario{palavra: "definição de teste"} - dictionary.Delete(word) + dicionario.Deleta(palavra) - _, err := dictionary.Search(word) - if err != ErrNotFound { - t.Errorf("Expected '%s' to be deleted", word) + _, err := dicionario.Busca(palavra) + if err != ErrNaoEncontrado { + t.Errorf("espera-se que '%s' seja deletado", palavra) } } ``` -Our test creates a `Dictionary` with a word and then checks if the word has been removed. +Nosso teste cria um `Dicionario` com uma palavra e depois verifica se a palavra foi removida. -## Try to run the test +## Execute o teste -By running `go test` we get: +Executando `go test` obtemos: -```text -./dictionary_test.go:74:6: dictionary.Delete undefined (type Dictionary has no field or method Delete) +```bash +./dicionario_test.go:74:6: dicionario.Deleta undefined (type Dicionario has no field or method Deleta) ``` -## Write the minimal amount of code for the test to run and check the failing test output +`dicionario.Deleta não definido (tipo Dicionario não tem campo ou método Deleta)` + +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado ```go -func (d Dictionary) Delete(word string) { +func (d Dicionario) Deleta(palavra string) { } ``` -After we add this, the test tells us we are not deleting the word. +Depois que adicionamos isso, o teste nos diz que não estamos deletando a palavra. -```text -dictionary_test.go:78: Expected 'test' to be deleted +```bash +dicionario_test.go:78: espera-se que 'teste' seja deletado ``` ## Escreva código o suficiente para fazer o teste passar ```go -func (d Dictionary) Delete(word string) { - delete(d, word) +func (d Dicionario) Deleta(palavra string) { + delete(d, palavra) } ``` -Go has a built-in function `delete` that works on maps. It takes two arguments. The first is the map and the second is the key to be removed. +Go tem uma função nativa chamada `delete` que funciona em maps. Ela leva dois argumentos: o primeiro é o map e o segundo é a chave a ser removida. -The `delete` function returns nothing, and we based our `Delete` method on the same notion. Since deleting a value that's not there has no effect, unlike our `Update` and `Add` methods, we don't need to complicate the API with errors. +A função `delete` não retorna nada, e baseamos nosso método `Deleta` nesse conceito. Já que deletar um valor não tem nenhum efeito, diferentemente dos nossos métodos `Atualiza` e `Adiciona`, não precisamos complicar a API com erros. -## Wrapping up +## Resumo -In this section, we covered a lot. We made a full CRUD \(Create, Read, Update and Delete\) API for our dictionary. Throughout the process we learned how to: +Nessa seção, falamos sobre muita coisa. Criamos uma API CRUD (Criar, Ler, Atualizar e Deletar) completa para nosso dicionário. No decorrer do processo, aprendemos como: -- Create maps -- Search for items in maps -- Add new items to maps -- Update items in maps -- Delete items from a map -- Learned more about errors - - How to create errors that are constants - - Writing error wrappers +- Criar maps +- Buscar por itens em maps +- Adicionar novos itens aos maps +- Atualizar itens em maps +- Deletar itens de um map +- Aprendemos mais sobre erros + - Como criar erros que são constantes + - Escrever wrappers de erro From 05a2354d484295e7ea87b59518bcc46e470371e3 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Tue, 30 Jul 2019 21:46:12 -0300 Subject: [PATCH 08/10] =?UTF-8?q?Corre=C3=A7=C3=A3o=20do=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 1e50dfce..26260c39 100644 --- a/README.md +++ b/README.md @@ -26,18 +26,16 @@ 3. [Inteiros](primeiros-passos-com-go/integers.md) - Mais conteúdo sobre sintaxe de declaração de função e aprenda novas formas de melhorar a documentação do seu código. 4. [Iteração](primeiros-passos-com-go/iteracao.md) - Aprenda sobre `for` e benchmarking. 5. [Arrays e slices](primeiros-passos-com-go/arrays-e-slices.md) - Aprenda sobre arrays, slices, `len`, variáveis recebidas como argumentos, `range` e cobertura de testes. -6. [Iteração](primeiros-passos-com-go/iteracao.md) - Aprenda sobre `for` e benchmarking. -7. [Arrays e slices](primeiros-passos-com-go/arrays-and-slices.md) - Aprenda sobre arrays, slices, `len`, varargs, `range` e cobertura de testes. -8. [Estruturas, métodos e interfaces](primeiros-passos-com-go/structs-methods-and-interfaces.md) - Aprenda sobre `structs`, métodos, `interface` e testes orientados a tabela \(table driven tests\). -9. [Ponteiros e erros](primeiros-passos-com-go/pointers-and-errors.md) - Aprenda sobre ponteiros e erros. -10. [Maps](primeiros-passos-com-go/maps.md) - Aprenda sobre armazenamento de valores na estrutura de dados `map`. -11. [Injeção de dependência](primeiros-passos-com-go/dependency-injection.md) - Aprenda sobre injeção de dependência, qual sua relação com interfaces e uma introdução a io. -12. [Mocking](primeiros-passos-com-go/mocking.md) - Use injeção de dependência com mocking para testar um código sem nenhum teste. -13. [Concorrência](primeiros-passos-com-go/concurrency.md) - Aprenda como escrever código concorrente para tornar seu software mais rápido. -14. [Select](primeiros-passos-com-go/select.md) - Aprenda a sincronizar processos assíncronos de forma elegante. -15. [Reflection](primeiros-passos-com-go/reflection.md) - Aprenda sobre reflection. -16. [Sync](primeiros-passos-com-go/sync.md) - Conheça algumas funcionalidades do pacote sync, como `WaitGroup` e `Mutex`. -17. [Context](primeiros-passos-com-go/context.md) - Use o pacote context para gerenciar e cancelar processos de longa duração. +6. [Estruturas, métodos e interfaces](primeiros-passos-com-go/structs-methods-and-interfaces.md) - Aprenda sobre `structs`, métodos, `interface` e testes orientados a tabela \(table driven tests\). +7. [Ponteiros e erros](primeiros-passos-com-go/pointers-and-errors.md) - Aprenda sobre ponteiros e erros. +8. [Maps](primeiros-passos-com-go/maps.md) - Aprenda sobre armazenamento de valores na estrutura de dados `map`. +9. [Injeção de dependência](primeiros-passos-com-go/dependency-injection.md) - Aprenda sobre injeção de dependência, qual sua relação com interfaces e uma introdução a io. +10. [Mocking](primeiros-passos-com-go/mocking.md) - Use injeção de dependência com mocking para testar um código sem nenhum teste. +11. [Concorrência](primeiros-passos-com-go/concurrency.md) - Aprenda como escrever código concorrente para tornar seu software mais rápido. +12. [Select](primeiros-passos-com-go/select.md) - Aprenda a sincronizar processos assíncronos de forma elegante. +13. [Reflection](primeiros-passos-com-go/reflection.md) - Aprenda sobre reflection. +14. [Sync](primeiros-passos-com-go/sync.md) - Conheça algumas funcionalidades do pacote sync, como `WaitGroup` e `Mutex`. +15. [Context](primeiros-passos-com-go/context.md) - Use o pacote context para gerenciar e cancelar processos de longa duração. ### Crie uma aplicação From 6a5e3b14a563b0b51e8a2e4c5f9ec171b534e9ee Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Fri, 2 Aug 2019 15:02:02 -0300 Subject: [PATCH 09/10] =?UTF-8?q?Revis=C3=A3o=20de=20maps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maps/v1/dicionario_test.go | 6 +- primeiros-passos-com-go/maps.md | 200 ++++++++++++++++---------------- 2 files changed, 100 insertions(+), 106 deletions(-) diff --git a/maps/v1/dicionario_test.go b/maps/v1/dicionario_test.go index 08969a01..50e52459 100644 --- a/maps/v1/dicionario_test.go +++ b/maps/v1/dicionario_test.go @@ -8,13 +8,13 @@ func TestBusca(t *testing.T) { resultado := dicionario.Busca("teste") esperado := "isso é apenas um teste" - compararStrings(t, resultado, esperado) + comparaStrings(t, resultado, esperado) } -func compararStrings(t *testing.T, resultado, esperado string) { +func comparaStrings(t *testing.T, resultado, esperado string) { t.Helper() if resultado != esperado { - t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "test") + t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "teste") } } diff --git a/primeiros-passos-com-go/maps.md b/primeiros-passos-com-go/maps.md index 9457fa82..d6f8a9f8 100644 --- a/primeiros-passos-com-go/maps.md +++ b/primeiros-passos-com-go/maps.md @@ -2,11 +2,11 @@ [**Você pode encontrar todos os códigos para esse capítulo aqui**](https://github.com/larien/learn-go-with-tests/tree/master/maps) -Em [arrays e slices](primeiros-passos-com-go/arrays-e-slices.md), vimos como armazenas valores em ordem. Agora, vamos descobrir uma forma de armazenar itens por uma `chave` (chave) e procurar por ela rapidamente. +Em [arrays e slices](primeiros-passos-com-go/arrays-e-slices.md), vimos como armazenar valores em ordem. Agora, vamos descobrir uma forma de armazenar itens por uma `key` (chave) e procurar por ela rapidamente. -Maps te permitem armazenar itens de forma parecida com a de um dicionário. Você pode pensar na `chave` como a palavra e o `valor` como a definição. E que forma melhor de aprender sobre Maps do que criar seu próprio dicionário? +Maps te permitem armazenar itens de forma parecida com a de um dicionário. Você pode pensar na `chave` como a palavra e o `valor` como a definição. E tem forma melhor de aprender sobre maps do que criar seu próprio dicionário? -Primeiro, vamos presumir que já temos algumas palavras com suas definições no dicionário. Se procurarmos por uma palavra, ele deve retornar sua definição. +Primeiro, vamos presumir que já temos algumas palavras com suas definições no dicionário. Se procurarmos por uma palavra, o dicionário deve retornar sua definição. ## Escreva o teste primeiro @@ -29,9 +29,9 @@ func TestBusca(t *testing.T) { } ``` -Declarar um Map é bem parecido com um array. A diferença é que começa com a palavra-chave `map` e requer dois tipos. O primeiro é o tipo da chave, que é escrito dentro de `[]`. O segundo é o tipo do valor, que vai logo após o `[]`. +Declarar um map é bem parecido com declarar um array. A diferença é que começa com a palavra-chave `map` e requer dois tipos. O primeiro é o tipo da chave, que é escrito dentro de `[]`. O segundo é o tipo do valor, que vai logo após o `[]`. -O tipo da chave é especial. Só pode ser um tipo comparável, porque sem a habilidade de dizer se duas chaves são iguais, não temos como certificar de que estamos obtendo o valor correto. Tipos comparáveis são explicados com detalhes na [especificação da linguagem](https://golang.org/ref/spec#Comparison_operators). +O tipo da chave é especial. Só pode ser um tipo comparável, porque sem a habilidade de dizer se duas chaves são iguais, não temos como ter certeza de que estamos obtendo o valor correto. Tipos comparáveis são explicados com detalhes na [especificação da linguagem](https://golang.org/ref/spec#Comparison_operators) (em inglês). O tipo do valor, por outro lado, pode ser o tipo que quiser. Pode até ser outro map. @@ -41,7 +41,7 @@ O restante do teste já deve ser familiar para você. Ao executar `go test`, o compilador vai falhar com `./dicionario_test.go:8:9: undefined: Busca`. -## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste falhado +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado Em `dicionario.go`: @@ -65,7 +65,7 @@ func Busca(dicionario map[string]string, palavra string) string { } ``` -Obter um valor de um Map é igual a obter um valor de um Array: `map[chave]`. +Obter um valor de um map é igual a obter um valor de um array: `map[chave]`. ## Refatoração @@ -76,23 +76,23 @@ func TestBusca(t *testing.T) { resultado := Busca(dicionario, "teste") esperado := "isso é apenas um teste" - compararStrings(t, resultado, esperado) + comparaStrings(t, resultado, esperado) } -func compararStrings(t *testing.T, resultado, esperado string) { - t.Helper() +func comparaStrings(t *testing.T, resultado, esperado string) { + t.Helper() - if resultado != esperado { - t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "test") + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s', dado '%s'", resultado, esperado, "teste") } } ``` -Decidi criar um helper `compararStrings` para tornar a implementação mais genérica. +Decidi criar um helper `comparaStrings` para tornar a implementação mais genérica. ### Usando um tipo personalizado -Podemos melhorar o uso do nosso dicionário criando um novo tipo baseado no map e fazendo a `Busca` virar um método. +Podemos melhorar o uso do nosso dicionário criando um novo tipo baseado no map e transformando a `Busca` em um método. Em `dicionario_test.go`: @@ -103,7 +103,7 @@ func TestBusca(t *testing.T) { resultado := dictionary.Busca("teste") esperado := "isso é apenas um teste" - compararStrings(t, resultado, esperado) + comparaStrings(t, resultado, esperado) } ``` @@ -117,7 +117,7 @@ Em `dicionario.go`: type Dicionario map[string]string func (d Dicionario) Busca(palavra string) string { - return d[palavra] + return d[palavra] } ``` @@ -127,26 +127,26 @@ Aqui criamos um tipo `Dicionario` que trabalha em cima da abstração de `map`. A busca básica foi bem fácil de implementar, mas o que acontece se passarmos uma palavra que não está no nosso dicionário? -Como o código está agora, não recebemos nada de volta. Isso é bom porque o programa continua a ser executado, mas há uma abordagem melhor. A função pode reportar que a palavra não está no dicionário. Dessa forma, o usuário não fica se perguntando se a palavra não existe ou se apenas não existe definição para ela (isso pode não parecer tão útil para um dicionário. No entanto, é um caso que pode ser essencial em outros casos de usos). +Com o código atual, não recebemos nada de volta. Isso é bom porque o programa continua a ser executado, mas há uma abordagem melhor. A função pode reportar que a palavra não está no dicionário. Dessa forma, o usuário não fica se perguntando se a palavra não existe ou se apenas não existe definição para ela (isso pode não parecer tão útil para um dicionário. No entanto, é um caso que pode ser essencial em outros casos de uso). ```go func TestBusca(t *testing.T) { - dicionario := Dicionario{"teste": "isso é apenas um teste"} + dicionario := Dicionario{"teste": "isso é apenas um teste"} - t.Run("palavra conhecida", func(t *testing.T) { - resultado, _ := dicionario.Busca("teste") - esperado := "isso é apenas um teste" + t.Run("palavra conhecida", func(t *testing.T) { + resultado, _ := dicionario.Busca("teste") + esperado := "isso é apenas um teste" - comparaStrings(t, resultado, esperado) - }) + comparaStrings(t, resultado, esperado) + }) - t.Run("palavra desconhecida", func(t *testing.T) { - _, resultado := dicionario.Busca("desconhecida") + t.Run("palavra desconhecida", func(t *testing.T) { + _, resultado := dicionario.Busca("desconhecida") - if err == nil { + if err == nil { t.Fatal("é esperado que um erro seja obtido.") } - }) + }) } ``` @@ -158,13 +158,11 @@ Erros podem ser convertidos para uma string com o método `.Error()`, o que pode Isso não vai compilar. -This does not compile - `./dictionary_test.go:18:10: assignment mismatch: 2 variables but 1 values` `incompatibilidade de atribuição: 2 variáveis, mas 1 valor` -## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste falhado +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado ```go func (d Dicionario) Busca(palavra string) (string, error) { @@ -193,7 +191,7 @@ func (d Dicionario) Busca(palavra string) (string, error) { Para fazê-lo passar, estamos usando uma propriedade interessante ao percorrer o map. Ele pode retornar dois valores. O segundo valor é uma boleana que indica se a chave foi encontrada com sucesso. -Essa propriedade nos permite diferenciar entre uma palavra que não existe e uma palavra que só não tem uma definição. +Essa propriedade nos permite diferenciar entre uma palavra que não existe e uma palavra que simplesmente não tem uma definição. ## Refatoração @@ -216,7 +214,7 @@ Podemos nos livrar do "erro mágico" na nossa função de `Busca` extraindo-o pa t.Run("palavra desconhecida", func(t *testing.T) { _, resultado := dicionario.Busca("desconhecida") - comparaErro(t, resultado, ErrNotFound) + comparaErro(t, resultado, ErrNaoEncontrado) }) func comparaErro(t *testing.T, resultado, esperado error) { @@ -253,7 +251,7 @@ func TestAdiciona(t *testing.T) { Nesse teste, estamos utilizando nossa função `Busca` para tornar a validação do dicionário um pouco mais fácil. -## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste falhado +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado Em `dicionario.go` @@ -272,7 +270,7 @@ dicionario_test.go:31: deveria ter encontrado palavra adicionada: não foi poss ```go func (d Dicionario) Adiciona(palavra, definicao string) { - d[palavra] = definicao + d[palavra] = definicao } ``` @@ -280,19 +278,19 @@ Adicionar coisas a um map também é bem semelhante a um array. Você só precis ### Tipos Referência -Uma propriedade interessante dos maps é que você pode modificá-los sem passá-los como ponteiro. Isso é porque o `map` é um tipo referência. Isso significa que ele contém uma referência à estrutura de dado subjacente, assim como um ponteiro. A estrutura de data subjacente é uma `tabela de dispersão` ou `mapa de hash`, e você pode ler mais sobre [aqui](https://pt.wikipedia.org/wiki/Tabela_de_dispers%C3%A3o). +Uma propriedade interessante dos maps é que você pode modificá-los sem passá-los como ponteiro. Isso é porque o `map` é um tipo referência. Isso significa que ele contém uma referência à estrutura de dado que estamos utilizando, assim como um ponteiro. Logo, quando criamos passamos o map como parâmetro, estamos alterando o map original e não sua cópia. A estrutura de dados utilizada é uma `tabela de dispersão` ou `mapa de hash`, e você pode ler mais sobre [aqui](https://pt.wikipedia.org/wiki/Tabela_de_dispers%C3%A3o). -É muito bom referenciar um map, porque não importa o tamanho do map, só vai haver uma cópia. +É muito bom ter o map como referência, porque não importa o tamanho do map, só vai haver uma cópia. -Um conceito que os tipos referência apresentam é que maps podem ser um valor `nil`. Um map `nil` se comporta como um map vazio durante a leitura,mas tentar inserir coisas em um map `nil` gera um panic em tempo de execução. Você pode saber mais sobre maps [aqui](https://blog.golang.org/go-maps-in-action) (em inglês). +Um conceito que os tipos referência apresentam é que maps podem ser um valor `nil`. Um map `nil` se comporta como um map vazio durante a leitura, mas tentar inserir coisas em um map `nil` gera um panic em tempo de execução. Você pode saber mais sobre maps [aqui](https://blog.golang.org/go-maps-in-action) (em inglês). -Além disso, você nunca deve inicializar um map vazio: +Além disso, você nunca deve inicializar um map vazio, como: ```go var m map[string]string ``` -Ao invés disso, você pode inicializar um map vazio como fizemos lá em cima, ou usando a palavra-chave `make` para criar um map para você:` keyword to create a map for you: +Ao invés disso, você pode inicializar um map vazio como fizemos lá em cima, ou usando a palavra-chave `make` para criar um map para você: ```go dicionario = map[string]string{} @@ -306,30 +304,30 @@ Ambas as abordagens criam um `hash map` vazio e apontam um `dicionario` para ele ## Refatoração -Não há muito para refatorar na nossa implementação, mas podemos simplificar o teste um pouco. +Não há muito para refatorar na nossa implementação, mas podemos simplificar o teste. ```go func TestAdiciona(t *testing.T) { - dicionario := Dicionario{} - palavra := "teste" - definicao := "isso é apenas um teste" + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" - dicionario.Adiciona(palavra, definicao) + dicionario.Adiciona(palavra, definicao) - comparaDefinicao(t, dicionario, palavra, definicao) + comparaDefinicao(t, dicionario, palavra, definicao) } func comparaDefinicao(t *testing.T, dicionario Dicionario, palavra, definicao string) { - t.Helper() + t.Helper() - resultado, err := dicionario.Busca(palavra) - if err != nil { - t.Fatal("deveria ter encontrado palavra adicionada:", err) - } + resultado, err := dicionario.Busca(palavra) + if err != nil { + t.Fatal("deveria ter encontrado palavra adicionada:", err) + } - if definicao != resultado { - t.Errorf("resultado '%s', esperado '%s'", resultado, definicao) - } + if definicao != resultado { + t.Errorf("resultado '%s', esperado '%s'", resultado, definicao) + } } ``` @@ -337,32 +335,32 @@ Criamos variáveis para palavra e definição e movemos a comparação da defini Nosso `Adiciona` está bom. No entanto, não consideramos o que acontece quando o valor que estamos tentando adicionar já existe! -O map não vai mostrar um erro se o valor já existe. Ao invés disso, elas vão sobrescrever o valor com o novo recebido. Isso pode ser conveniente na prática, mas torna o nome da nossa função muito menos preciso. `Adiciona` não deve modificar valores existentes. Só deve adicionar palavras novas ao nosso dicionário. +O map não vai mostrar um erro se o valor já existe. Ao invés disso, ele vai sobrescrever o valor com o novo recebido. Isso pode ser conveniente na prática, mas torna o nome da nossa função muito menos preciso. `Adiciona` não deve modificar valores existentes. Só deve adicionar palavras novas ao nosso dicionário. ## Escreva o teste primeiro ```go func TestAdiciona(t *testing.T) { - t.Run("palavra nova", func(t *testing.T) { - dicionario := Dicionario{} - palavra := "teste" - definicao := "isso é apenas um teste" - - err := dicionario.Adiciona(palavra, definicao) - - comparaErro(t, err, nil) - comparaDefinicao(t, dicionario, palavra, definicao) - }) - - t.Run("palavra existente", func(t *testing.T) { - palavra := "teste" - definicao := "isso é apenas um teste" - dicionario := Dicionario{palavra: definicao} - err := dicionario.Add(palavra, "teste novo") - - comparaErro(t, err, ErrPalavraExistente) - comparaDefinicao(t, dicionario, palavra, definicao) - }) + t.Run("palavra nova", func(t *testing.T) { + dicionario := Dicionario{} + palavra := "teste" + definicao := "isso é apenas um teste" + + err := dicionario.Adiciona(palavra, definicao) + + comparaErro(t, err, nil) + comparaDefinicao(t, dicionario, palavra, definicao) + }) + + t.Run("palavra existente", func(t *testing.T) { + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + err := dicionario.Add(palavra, "teste novo") + + comparaErro(t, err, ErrPalavraExistente) + comparaDefinicao(t, dicionario, palavra, definicao) + }) } ``` @@ -379,9 +377,9 @@ Agora o compilador vai falhar porque não estamos devolvendo um valor para `Adic `usado como valor` -## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste falhado +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado -Em `dicionario.go` +Em `dicionario.go`: ```go var ( @@ -397,8 +395,6 @@ func (d Dicionario) Adiciona(palavra, definicao string) error { Agora temos mais dois erros. Ainda estamos modificando o valor e retornando um erro `nil`. -Now we get two more errors. We are still modifying the value, and returning a `nil` error. - ```bash dicionario_test.go:43: resultado erro '%!s()', esperado 'não é possível adicionar a palavra pois ela já existe' dicionario_test.go:44: resultado 'teste novo', esperado 'isso é apenas um teste' @@ -450,14 +446,14 @@ Agora, vamos criar uma função que `Atualiza` a definição de uma palavra. ```go func TestUpdate(t *testing.T) { - palavra := "teste" - definicao := "isso é apenas um teste" - dicionario := Dicionario{palavra: definicao} - novaDefinicao := "nova definição" + palavra := "teste" + definicao := "isso é apenas um teste" + dicionario := Dicionario{palavra: definicao} + novaDefinicao := "nova definição" - dicionario.Atualiza(palavra, novaDefinicao) + dicionario.Atualiza(palavra, novaDefinicao) - comparaDefinicao(t, dicionario, palavra, novaDefinicao) + comparaDefinicao(t, dicionario, palavra, novaDefinicao) } ``` @@ -481,23 +477,21 @@ func (d Dicionario) Atualiza(palavra, definicao string) {} Feito isso, somos capazes de ver o que precisamos para mudar a definição da palavra. -With that in place, we are able to see that we need to change the definition of the word. - ```bash dicionario_test.go:55: resultado 'isso é apenas um teste', esperado 'nova definição' ``` ## Escreva código o suficiente para fazer o teste passar -Já vimos como fazer essa implementação quando corrigimos o problema com `Adiciona`. Logo, vamos implementar algo bem parecido a `Adiciona`. +Já vimos como fazer essa implementação quando corrigimos o problema com `Adiciona`. Logo, vamos implementar algo bem parecido com `Adiciona`. ```go func (d Dicionario) Atualiza(palavra, definicao string) { - d[palavra] = definicao + d[palavra] = definicao } ``` -Não há refatoração necessária, já que foi uma mudança simples. No entanto, agora temos o mesmo problema com `Adiciona`. Se passarmos uma palavra nova, `Atualiza` vai adicioná-la no dicionário. +Não é necessário fazer refatorar nada, já que foi uma mudança simples. No entanto, agora temos o mesmo problema com `Adiciona`. Se passarmos uma palavra nova, `Atualiza` vai adicioná-la no dicionário. ## Escreva o teste primeiro @@ -563,18 +557,18 @@ dicionario_test.go:66: resultado erro '%!s()', esperado 'não foi possível ```go func (d Dicionario) Atualiza(palavra, definicao string) error { - _, err := d.Busca(palavra) - switch err { - case ErrNaoEncontrado: - return ErrPalavraInexistente - case nil: - d[palavra] = definicao - default: - return err - - } - - return nil + _, err := d.Busca(palavra) + switch err { + case ErrNaoEncontrado: + return ErrPalavraInexistente + case nil: + d[palavra] = definicao + default: + return err + + } + + return nil } ``` @@ -636,7 +630,7 @@ dicionario_test.go:78: espera-se que 'teste' seja deletado ```go func (d Dicionario) Deleta(palavra string) { - delete(d, palavra) + delete(d, palavra) } ``` @@ -655,4 +649,4 @@ Nessa seção, falamos sobre muita coisa. Criamos uma API CRUD (Criar, Ler, Atua - Deletar itens de um map - Aprendemos mais sobre erros - Como criar erros que são constantes - - Escrever wrappers de erro + - Escrever encapsuladores de erro From 4b5f09e3f0367f10053dcbaab474be7817d85782 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Wed, 7 Aug 2019 15:21:59 -0300 Subject: [PATCH 10/10] Text review fixes --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 26260c39..75d2f127 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ 6. [Estruturas, métodos e interfaces](primeiros-passos-com-go/structs-methods-and-interfaces.md) - Aprenda sobre `structs`, métodos, `interface` e testes orientados a tabela \(table driven tests\). 7. [Ponteiros e erros](primeiros-passos-com-go/pointers-and-errors.md) - Aprenda sobre ponteiros e erros. 8. [Maps](primeiros-passos-com-go/maps.md) - Aprenda sobre armazenamento de valores na estrutura de dados `map`. -9. [Injeção de dependência](primeiros-passos-com-go/dependency-injection.md) - Aprenda sobre injeção de dependência, qual sua relação com interfaces e uma introdução a io. +9. [Injeção de dependência](primeiros-passos-com-go/dependency-injection.md) - Aprenda sobre injeção de dependência, qual sua relação com interfaces e uma introdução a I/O. 10. [Mocking](primeiros-passos-com-go/mocking.md) - Use injeção de dependência com mocking para testar um código sem nenhum teste. 11. [Concorrência](primeiros-passos-com-go/concurrency.md) - Aprenda como escrever código concorrente para tornar seu software mais rápido. 12. [Select](primeiros-passos-com-go/select.md) - Aprenda a sincronizar processos assíncronos de forma elegante. 13. [Reflection](primeiros-passos-com-go/reflection.md) - Aprenda sobre reflection. -14. [Sync](primeiros-passos-com-go/sync.md) - Conheça algumas funcionalidades do pacote sync, como `WaitGroup` e `Mutex`. -15. [Context](primeiros-passos-com-go/context.md) - Use o pacote context para gerenciar e cancelar processos de longa duração. +14. [Sync](primeiros-passos-com-go/sync.md) - Conheça algumas funcionalidades do pacote `sync`, como `WaitGroup` e `Mutex`. +15. [Context](primeiros-passos-com-go/context.md) - Use o pacote `context` para gerenciar e cancelar processos de longa duração. ### Crie uma aplicação