From db75d6f2d9efd6913a4850f5794d0f929ddcf9f1 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Sat, 4 Sep 2021 00:32:35 -0400 Subject: [PATCH 01/16] zero_zilch_nada: remove ambiguous reference to empty In Go, there can be a difference between a type's zero value and its empty value. For example, consider the following code snippet: ```go func main() { var s1 []string fmt.Printf("%#v\n", s1) if s1 == nil { fmt.Println("s1 is equal to nil") } s2 := []string{} fmt.Printf("%#v\n", s2) if s2 == nil { fmt.Println("s2 is equal to nil") } } ``` The variable `s1` will be set to its zero value (`nil`) whereas the variable `s2` will be set to a slice of strings with zero elements. This behavior makes the term "empty" ambiguous and may confuse students as they continue learning about Go. In addition to code updates, the exercise text was updated to introduce the `var` keyword as well as various verbiage updates. --- .../concept/zero-zilch-nada/.docs/hints.md | 22 +++--- .../zero-zilch-nada/.docs/instructions.md | 41 +++++------ .../zero-zilch-nada/.docs/introduction.md | 58 +++++++++++++-- .../concept/zero-zilch-nada/.meta/config.json | 1 + .../concept/zero-zilch-nada/.meta/design.md | 8 +-- .../concept/zero-zilch-nada/.meta/exemplar.go | 36 +++++----- .../zero-zilch-nada/zero_zilch_nada.go | 54 +++++++------- .../zero-zilch-nada/zero_zilch_nada_test.go | 72 +++++++++---------- 8 files changed, 169 insertions(+), 123 deletions(-) diff --git a/exercises/concept/zero-zilch-nada/.docs/hints.md b/exercises/concept/zero-zilch-nada/.docs/hints.md index eac1022de..11fdaf752 100644 --- a/exercises/concept/zero-zilch-nada/.docs/hints.md +++ b/exercises/concept/zero-zilch-nada/.docs/hints.md @@ -9,39 +9,39 @@ } ``` -## 1. Return an empty bool +## 1. Return a bool set to its zero value - The zero value for the bool type is `false`. -## 2. Return an empty int +## 2. Return an int set to its zero value -- The zero value for numeric types is 0. +- The zero value for numeric types is `0`. -## 3. Return an empty string +## 3. Return a string set to its zero value -- The zero value for the string type is the empty string "". +- The zero value for the string type is the empty string `""`. -## 4. Return an empty func +## 4. Return a func set to its zero value - The zero value for the func type is `nil`. -## 5. Return an empty pointer +## 5. Return a pointer set to its zero value - The zero value for the pointer type is `nil`. -## 6. Return an empty map +## 6. Return a map set to its zero value - The zero value for the map type is `nil`. -## 7. Return an empty slice +## 7. Return a slice set to its zero value - The zero value for the slice type is `nil`. -## 8. Return an empty channel +## 8. Return a channel set to its zero value - The zero value for the channel type is `nil`. -## 9. Return an empty interface +## 9. Return an interface set to its zero value - The zero value for the interface type is `nil`. diff --git a/exercises/concept/zero-zilch-nada/.docs/instructions.md b/exercises/concept/zero-zilch-nada/.docs/instructions.md index 5c2f669ef..be33181a2 100644 --- a/exercises/concept/zero-zilch-nada/.docs/instructions.md +++ b/exercises/concept/zero-zilch-nada/.docs/instructions.md @@ -1,40 +1,41 @@ # Instructions -In this exercise, we will write some simple functions that return zero values for various Go types. Some types -you might not have seen before. They will be introduced in detail in later exercises. +In this exercise, we will write some functions that return the zero value for +Go's types. You may not have seen some of the types yet. They will be +introduced in detail in later exercises. -## 1. Return an empty bool +## 1. Return a bool set to its zero value -Adjust the `EmptyBool` function to return an empty bool. +Adjust the `ZeroBool` function to return the zero value for a bool. -## 2. Return an empty int +## 2. Return an int set to its zero value -Adjust the `EmptyInt` function to return an empty int. +Adjust the `ZeroInt` function to return the zero value for an int. -## 3. Return an empty string +## 3. Return a string set to its zero value -Adjust the `EmptyString` function to return an empty string. +Adjust the `ZeroString` function to return the zero value for a string. -## 4. Return an empty func +## 4. Return a func set to its zero value -Adjust the `EmptyFunc` function to return an empty func. +Adjust the `ZeroFunc` function to return the zero value for a func. -## 5. Return an empty pointer +## 5. Return a pointer set to its zero value -Adjust the `EmptyPointer` function to return an empty pointer. +Adjust the `ZeroPointer` function to return the zero value for a pointer. -## 6. Return an empty map +## 6. Return a map set to its zero value -Adjust the `EmptyMap` function to return an empty map. +Adjust the `ZeroMap` function to return the zero value for a map. -## 7. Return an empty slice +## 7. Return a slice set to its zero value -Adjust the `EmptySlice` function to return an empty slice. +Adjust the `ZeroSlice` function to return the zero value for a slice. -## 8. Return an empty channel +## 8. Return a channel set to its zero value -Adjust the `EmptyChannel` function to return an empty channel. +Adjust the `ZeroChannel` function to return the zero value for a channel. -## 9. Return an empty interface +## 9. Return an interface set to its zero value -Adjust the `EmptyInterface` function to return an empty interface. +Adjust the `ZeroInterface` function to return the zero value for an interface. diff --git a/exercises/concept/zero-zilch-nada/.docs/introduction.md b/exercises/concept/zero-zilch-nada/.docs/introduction.md index 15f648bc5..e3667805e 100644 --- a/exercises/concept/zero-zilch-nada/.docs/introduction.md +++ b/exercises/concept/zero-zilch-nada/.docs/introduction.md @@ -1,12 +1,12 @@ # Introduction -## Zero Value +Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. -## Nil +The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -In Go, uninitialized variables and their elements are given default values. +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. -These default values are called the zero values for their respective types: +The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | @@ -14,10 +14,54 @@ These default values are called the zero values for their respective types: | numeric | 0 | | string | "" | | pointer | nil | -| func | nil | | interface | nil | -| slice | nil | | channel | nil | | map | nil | +| slice | nil | +| func | nil | + +## Zero Value Construction + +The `var` keyword can be used to construct any type to its zero value: + +```go +func main() { + var myBool bool + fmt.Println(myBool) +} +``` + +```go +func main() { + var myMap map[int]int + fmt.Println(myMap) +} +``` + +## Comparing Types to Nil + +Comparing a type whose zero value is not `nil` to `nil` is an error: + +```go +func main() { + var myString string + + if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) + fmt.Println(myString) + } +} +``` + +However, comparing a type whose zero value is `nil` to `nil` is acceptable: + +```go +func main() { + var mySlice []int + + if mySlice != nil { + fmt.Println(mySlice) + } +} +``` -The identifier `nil`, meaning zero, is the zero value for the more complex types in Go. +[zero_values]: https://golang.org/ref/spec#The_zero_value diff --git a/exercises/concept/zero-zilch-nada/.meta/config.json b/exercises/concept/zero-zilch-nada/.meta/config.json index 5cec9cc11..a25701d0f 100644 --- a/exercises/concept/zero-zilch-nada/.meta/config.json +++ b/exercises/concept/zero-zilch-nada/.meta/config.json @@ -4,6 +4,7 @@ "jamessouth" ], "contributors": [ + "sudomateo", "tehsphinx" ], "files": { diff --git a/exercises/concept/zero-zilch-nada/.meta/design.md b/exercises/concept/zero-zilch-nada/.meta/design.md index fb7165352..248aa7e58 100644 --- a/exercises/concept/zero-zilch-nada/.meta/design.md +++ b/exercises/concept/zero-zilch-nada/.meta/design.md @@ -2,18 +2,18 @@ ## Goal -The goal of this exercise is to teach the student about `nil` and other zero values. +The goal of this exercise is to teach the student about the zero value of Go's types. ## Learning objectives -- Go assigns zero values to uninitialized variables according to the type the variable holds. +- Variables declared without an explicit initial value default to the zero value for their respective type. +- The zero values for strings, numeric types, and booleans are `""`, `0`, and `false`, respectively. - The identifier `nil` is the zero value for pointers, channels, maps, interfaces, slices, and functions. -- Zero values for strings, numbers, and booleans are "", 0, and false, respectively. ## Out of scope - Error checking. -- `Nil` checking. +- `nil` checking. - Usage of the above-mentioned types. ## Concepts diff --git a/exercises/concept/zero-zilch-nada/.meta/exemplar.go b/exercises/concept/zero-zilch-nada/.meta/exemplar.go index 6d97598ed..361ef081a 100644 --- a/exercises/concept/zero-zilch-nada/.meta/exemplar.go +++ b/exercises/concept/zero-zilch-nada/.meta/exemplar.go @@ -1,46 +1,46 @@ package zero -// EmptyBool returns an empty (zero value) bool -func EmptyBool() bool { +// ZeroBool returns a bool set to its zero value. +func ZeroBool() bool { return false } -// EmptyInt returns an empty (zero value) int -func EmptyInt() int { +// ZeroInt returns an int set to its zero value. +func ZeroInt() int { return 0 } -// EmptyString returns an empty (zero value) string -func EmptyString() string { +// ZeroString returns a string set to its zero value. +func ZeroString() string { return "" } -// EmptyFunc returns an empty (zero value) func -func EmptyFunc() func() { +// ZeroFunc returns a func set to its zero value. +func ZeroFunc() func() { return nil } -// EmptyPointer returns an empty (zero value) pointer -func EmptyPointer() *int { +// ZeroPointer returns a pointer set to its zero value. +func ZeroPointer() *int { return nil } -// EmptyMap returns an empty (zero value) map -func EmptyMap() map[int]int { +// ZeroMap returns a map set to its zero value. +func ZeroMap() map[int]int { return nil } -// EmptySlice returns an empty (zero value) slice -func EmptySlice() []int { +// ZeroSlice returns a slice set to its zero value. +func ZeroSlice() []int { return nil } -// EmptyChannel returns an empty (zero value) channel -func EmptyChannel() chan int { +// ZeroChannel returns a channel set to its zero value. +func ZeroChannel() chan int { return nil } -// EmptyInterface returns an empty (zero value) interface -func EmptyInterface() interface{} { +// ZeroInterface returns an interface set to its zero value. +func ZeroInterface() interface{} { return nil } diff --git a/exercises/concept/zero-zilch-nada/zero_zilch_nada.go b/exercises/concept/zero-zilch-nada/zero_zilch_nada.go index 21e80467a..60b6bf911 100644 --- a/exercises/concept/zero-zilch-nada/zero_zilch_nada.go +++ b/exercises/concept/zero-zilch-nada/zero_zilch_nada.go @@ -1,46 +1,46 @@ package zero -// EmptyBool returns an empty (zero value) bool -func EmptyBool() bool { - panic("please implement the EmptyBool function") +// ZeroBool returns a bool set to its zero value. +func ZeroBool() bool { + panic("please implement the ZeroBool function") } -// EmptyInt returns an empty (zero value) int -func EmptyInt() int { - panic("please implement the EmptyInt function") +// ZeroInt returns an int set to its zero value. +func ZeroInt() int { + panic("please implement the ZeroInt function") } -// EmptyString returns an empty (zero value) string -func EmptyString() string { - panic("please implement the EmptyString function") +// ZeroString returns a string set to its zero value. +func ZeroString() string { + panic("please implement the ZeroString function") } -// EmptyFunc returns an empty (zero value) func -func EmptyFunc() func() { - panic("please implement the EmptyFunc function") +// ZeroFunc returns a func set to its zero value. +func ZeroFunc() func() { + panic("please implement the ZeroFunc function") } -// EmptyPointer returns an empty (zero value) pointer -func EmptyPointer() *int { - panic("please implement the EmptyPointer function") +// ZeroPointer returns a pointer set to its zero value +func ZeroPointer() *int { + panic("please implement the ZeroPointer function") } -// EmptyMap returns an empty (zero value) map -func EmptyMap() map[int]int { - panic("please implement the EmptyMap function") +// ZeroMap returns a map set to its zero value. +func ZeroMap() map[int]int { + panic("please implement the ZeroMap function") } -// EmptySlice returns an empty (zero value) slice -func EmptySlice() []int { - panic("please implement the EmptySlice function") +// ZeroSlice returns a slice set to its zero value. +func ZeroSlice() []int { + panic("please implement the ZeroSlice function") } -// EmptyChannel returns an empty (zero value) channel -func EmptyChannel() chan int { - panic("please implement the EmptyChannel function") +// ZeroChannel returns a channel set to its zero value. +func ZeroChannel() chan int { + panic("please implement the ZeroChannel function") } -// EmptyInterface returns an empty (zero value) interface -func EmptyInterface() interface{} { - panic("please implement the EmptyInterface function") +// ZeroInterface returns an interface set to its zero value. +func ZeroInterface() interface{} { + panic("please implement the ZeroInterface function") } diff --git a/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go b/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go index d0739d21a..430e1270f 100644 --- a/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go +++ b/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go @@ -5,137 +5,137 @@ import ( "testing" ) -func TestEmptyInterface(t *testing.T) { +func TestZeroInterface(t *testing.T) { test := struct { name string want interface{} }{ - "EmptyInterface", + "ZeroInterface", nil, } t.Run(test.name, func(t *testing.T) { - if got := EmptyInterface(); got != test.want { - t.Errorf("EmptyInterface() = %v, want %v", got, test.want) + if got := ZeroInterface(); got != test.want { + t.Errorf("ZeroInterface() = %v, want %v", got, test.want) } }) } -func TestEmptyMap(t *testing.T) { +func TestZeroMap(t *testing.T) { test := struct { name string want map[int]int }{ - "EmptyMap", + "ZeroMap", nil, } t.Run(test.name, func(t *testing.T) { - if got := EmptyMap(); got != nil { - t.Errorf("EmptyMap() = %v, want %v", got, test.want) + if got := ZeroMap(); got != nil { + t.Errorf("ZeroMap() = %v, want %v", got, test.want) } }) } -func TestEmptySlice(t *testing.T) { +func TestZeroSlice(t *testing.T) { test := struct { name string want []int }{ - "EmptySlice", + "ZeroSlice", nil, } t.Run(test.name, func(t *testing.T) { - if got := EmptySlice(); got != nil { - t.Errorf("EmptySlice() = %p, want %p", got, test.want) + if got := ZeroSlice(); got != nil { + t.Errorf("ZeroSlice() = %p, want %p", got, test.want) } }) } -func TestEmptyString(t *testing.T) { +func TestZeroString(t *testing.T) { test := struct { name string want string }{ - "EmptyString", + "ZeroString", "", } t.Run(test.name, func(t *testing.T) { - if got := EmptyString(); got != test.want { - t.Errorf("EmptyString() = %s, want %s", got, test.want) + if got := ZeroString(); got != test.want { + t.Errorf("ZeroString() = %s, want %s", got, test.want) } }) } -func TestEmptyChannel(t *testing.T) { +func TestZeroChannel(t *testing.T) { test := struct { name string want chan int }{ - "EmptyChannel", + "ZeroChannel", nil, } t.Run(test.name, func(t *testing.T) { - if got := EmptyChannel(); got != test.want { - t.Errorf("EmptyChannel() = %v, want %v", got, test.want) + if got := ZeroChannel(); got != test.want { + t.Errorf("ZeroChannel() = %v, want %v", got, test.want) } }) } -func TestEmptyPointer(t *testing.T) { +func TestZeroPointer(t *testing.T) { test := struct { name string want *int }{ - "EmptyPointer", + "ZeroPointer", nil, } t.Run(test.name, func(t *testing.T) { - if got := EmptyPointer(); got != test.want { - t.Errorf("EmptyPointer() = %v, want %v", got, test.want) + if got := ZeroPointer(); got != test.want { + t.Errorf("ZeroPointer() = %v, want %v", got, test.want) } }) } -func TestEmptyBool(t *testing.T) { +func TestZeroBool(t *testing.T) { test := struct { name string want bool }{ - "EmptyBool", + "ZeroBool", false, } t.Run(test.name, func(t *testing.T) { - if got := EmptyBool(); got != test.want { - t.Errorf("EmptyBool() = %t, want %t", got, test.want) + if got := ZeroBool(); got != test.want { + t.Errorf("ZeroBool() = %t, want %t", got, test.want) } }) } -func TestEmptyFunc(t *testing.T) { +func TestZeroFunc(t *testing.T) { test := struct { name string want func() }{ - "EmptyFunc", + "ZeroFunc", nil, } t.Run(test.name, func(t *testing.T) { - if got := EmptyFunc(); !reflect.DeepEqual(got, test.want) { - t.Errorf("EmptyFunc() = %p, want nil", got) + if got := ZeroFunc(); !reflect.DeepEqual(got, test.want) { + t.Errorf("ZeroFunc() = %p, want nil", got) } }) } -func TestEmptyInt(t *testing.T) { +func TestZeroInt(t *testing.T) { test := struct { name string want int }{ - "EmptyInt", + "ZeroInt", 0, } t.Run(test.name, func(t *testing.T) { - if got := EmptyInt(); got != test.want { - t.Errorf("EmptyInt() = %d, want %d", got, test.want) + if got := ZeroInt(); got != test.want { + t.Errorf("ZeroInt() = %d, want %d", got, test.want) } }) } From 4bc15ee20eae06a8e52d8ce6ef4481968a079fa6 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Sat, 4 Sep 2021 00:47:33 -0400 Subject: [PATCH 02/16] zero_zilch_nada: update related concept documentation Updated the documentation for the nil and zero-values concepts to better reflect the new `zero_zilch_nada` exercise content. Long term, I'd probably recommend merging the two concepts into one but for now keeping their content the same ensures that students will learn the relevant content regardless of which conept they click on. --- concepts/nil/.meta/config.json | 2 +- concepts/nil/about.md | 61 +++++++++++++++++++++----- concepts/nil/introduction.md | 58 +++++++++++++++++++++--- concepts/zero-values/.meta/config.json | 2 +- concepts/zero-values/about.md | 59 ++++++++++++++++++++----- concepts/zero-values/introduction.md | 60 +++++++++++++++++++++---- 6 files changed, 203 insertions(+), 39 deletions(-) diff --git a/concepts/nil/.meta/config.json b/concepts/nil/.meta/config.json index 10df2320f..ba4220247 100644 --- a/concepts/nil/.meta/config.json +++ b/concepts/nil/.meta/config.json @@ -1,5 +1,5 @@ { - "blurb": "TODO: add blurb", + "blurb": "Learn about nil.", "authors": [], "contributors": [] } diff --git a/concepts/nil/about.md b/concepts/nil/about.md index ff5e2c50d..e3667805e 100644 --- a/concepts/nil/about.md +++ b/concepts/nil/about.md @@ -1,8 +1,12 @@ -# Zero Values +# Introduction -Unlike some other languages, Go has no empty/null/undefined state for uninitialized variables. Every type has a [zero value][zero_values] that uninitialized variables will hold upon declaration. +Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. -These default values are called the zero values for their respective types: +The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. + +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. + +The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | @@ -10,21 +14,54 @@ These default values are called the zero values for their respective types: | numeric | 0 | | string | "" | | pointer | nil | -| func | nil | | interface | nil | -| slice | nil | | channel | nil | | map | nil | +| slice | nil | +| func | nil | -The predeclared identifier `nil`, meaning zero, is the zero value for the more complex types in Go. Comparing a type whose zero value is not `nil` to `nil`, like string, is an error: +## Zero Value Construction + +The `var` keyword can be used to construct any type to its zero value: ```go - func main() { - myString := "exercism" - if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) - fmt.Println(myString) - } - } +func main() { + var myBool bool + fmt.Println(myBool) +} +``` + +```go +func main() { + var myMap map[int]int + fmt.Println(myMap) +} +``` + +## Comparing Types to Nil + +Comparing a type whose zero value is not `nil` to `nil` is an error: + +```go +func main() { + var myString string + + if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) + fmt.Println(myString) + } +} +``` + +However, comparing a type whose zero value is `nil` to `nil` is acceptable: + +```go +func main() { + var mySlice []int + + if mySlice != nil { + fmt.Println(mySlice) + } +} ``` [zero_values]: https://golang.org/ref/spec#The_zero_value diff --git a/concepts/nil/introduction.md b/concepts/nil/introduction.md index 2576ccae8..e3667805e 100644 --- a/concepts/nil/introduction.md +++ b/concepts/nil/introduction.md @@ -1,8 +1,12 @@ # Introduction -In Go, uninitialized variables and their elements are given default values. +Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. -These default values are called the zero values for their respective types: +The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. + +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. + +The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | @@ -10,10 +14,54 @@ These default values are called the zero values for their respective types: | numeric | 0 | | string | "" | | pointer | nil | -| func | nil | | interface | nil | -| slice | nil | | channel | nil | | map | nil | +| slice | nil | +| func | nil | + +## Zero Value Construction + +The `var` keyword can be used to construct any type to its zero value: + +```go +func main() { + var myBool bool + fmt.Println(myBool) +} +``` + +```go +func main() { + var myMap map[int]int + fmt.Println(myMap) +} +``` + +## Comparing Types to Nil + +Comparing a type whose zero value is not `nil` to `nil` is an error: + +```go +func main() { + var myString string + + if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) + fmt.Println(myString) + } +} +``` + +However, comparing a type whose zero value is `nil` to `nil` is acceptable: + +```go +func main() { + var mySlice []int + + if mySlice != nil { + fmt.Println(mySlice) + } +} +``` -The identifier `nil`, meaning zero, is the zero value for the more complex types in Go. +[zero_values]: https://golang.org/ref/spec#The_zero_value diff --git a/concepts/zero-values/.meta/config.json b/concepts/zero-values/.meta/config.json index 10df2320f..6a4641833 100644 --- a/concepts/zero-values/.meta/config.json +++ b/concepts/zero-values/.meta/config.json @@ -1,5 +1,5 @@ { - "blurb": "TODO: add blurb", + "blurb": "Learn about zero values.", "authors": [], "contributors": [] } diff --git a/concepts/zero-values/about.md b/concepts/zero-values/about.md index ff5e2c50d..de5b7765e 100644 --- a/concepts/zero-values/about.md +++ b/concepts/zero-values/about.md @@ -1,8 +1,12 @@ # Zero Values -Unlike some other languages, Go has no empty/null/undefined state for uninitialized variables. Every type has a [zero value][zero_values] that uninitialized variables will hold upon declaration. +Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. -These default values are called the zero values for their respective types: +The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. + +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. + +The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | @@ -10,21 +14,54 @@ These default values are called the zero values for their respective types: | numeric | 0 | | string | "" | | pointer | nil | -| func | nil | | interface | nil | -| slice | nil | | channel | nil | | map | nil | +| slice | nil | +| func | nil | -The predeclared identifier `nil`, meaning zero, is the zero value for the more complex types in Go. Comparing a type whose zero value is not `nil` to `nil`, like string, is an error: +## Zero Value Construction + +The `var` keyword can be used to construct any type to its zero value: ```go - func main() { - myString := "exercism" - if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) - fmt.Println(myString) - } - } +func main() { + var myBool bool + fmt.Println(myBool) +} +``` + +```go +func main() { + var myMap map[int]int + fmt.Println(myMap) +} +``` + +## Comparing Types to Nil + +Comparing a type whose zero value is not `nil` to `nil` is an error: + +```go +func main() { + var myString string + + if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) + fmt.Println(myString) + } +} +``` + +However, comparing a type whose zero value is `nil` to `nil` is acceptable: + +```go +func main() { + var mySlice []int + + if mySlice != nil { + fmt.Println(mySlice) + } +} ``` [zero_values]: https://golang.org/ref/spec#The_zero_value diff --git a/concepts/zero-values/introduction.md b/concepts/zero-values/introduction.md index 8f13ac438..e3667805e 100644 --- a/concepts/zero-values/introduction.md +++ b/concepts/zero-values/introduction.md @@ -1,14 +1,12 @@ # Introduction -TODO: the content below is copied from the exercise introduction and probably needs rewriting to a proper concept introduction +Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. -## zero-value +The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -## nil +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. -In Go, uninitialized variables and their elements are given default values. - -These default values are called the zero values for their respective types: +The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | @@ -16,10 +14,54 @@ These default values are called the zero values for their respective types: | numeric | 0 | | string | "" | | pointer | nil | -| func | nil | | interface | nil | -| slice | nil | | channel | nil | | map | nil | +| slice | nil | +| func | nil | + +## Zero Value Construction + +The `var` keyword can be used to construct any type to its zero value: + +```go +func main() { + var myBool bool + fmt.Println(myBool) +} +``` + +```go +func main() { + var myMap map[int]int + fmt.Println(myMap) +} +``` + +## Comparing Types to Nil + +Comparing a type whose zero value is not `nil` to `nil` is an error: + +```go +func main() { + var myString string + + if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) + fmt.Println(myString) + } +} +``` + +However, comparing a type whose zero value is `nil` to `nil` is acceptable: + +```go +func main() { + var mySlice []int + + if mySlice != nil { + fmt.Println(mySlice) + } +} +``` -The identifier `nil`, meaning zero, is the zero value for the more complex types in Go. +[zero_values]: https://golang.org/ref/spec#The_zero_value From 136a0d1e0afe3559d68a339f74036eefcc66743d Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Sat, 4 Sep 2021 00:53:19 -0400 Subject: [PATCH 03/16] added missing period character --- exercises/concept/zero-zilch-nada/zero_zilch_nada.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/zero-zilch-nada/zero_zilch_nada.go b/exercises/concept/zero-zilch-nada/zero_zilch_nada.go index 60b6bf911..09305e805 100644 --- a/exercises/concept/zero-zilch-nada/zero_zilch_nada.go +++ b/exercises/concept/zero-zilch-nada/zero_zilch_nada.go @@ -20,7 +20,7 @@ func ZeroFunc() func() { panic("please implement the ZeroFunc function") } -// ZeroPointer returns a pointer set to its zero value +// ZeroPointer returns a pointer set to its zero value. func ZeroPointer() *int { panic("please implement the ZeroPointer function") } From 305dcf372e7aeef1b2c8aec7c4c8464960bf3918 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Thu, 9 Sep 2021 23:44:11 -0400 Subject: [PATCH 04/16] Update concept documentation and exercise code Updated the concept documentation to focus on zero values. Changed the exercise to be a bit more involved than the previous one-liner. --- concepts/zero-values/.meta/config.json | 4 +- concepts/zero-values/about.md | 58 ++--- concepts/zero-values/introduction.md | 68 +---- concepts/zero-values/links.json | 7 +- .../concept/zero-zilch-nada/.docs/hints.md | 22 +- .../zero-zilch-nada/.docs/instructions.md | 40 ++- .../zero-zilch-nada/.docs/introduction.md | 68 +---- .../concept/zero-zilch-nada/.meta/design.md | 1 - .../concept/zero-zilch-nada/.meta/exemplar.go | 79 ++++-- .../zero-zilch-nada/zero_zilch_nada.go | 54 ++-- .../zero-zilch-nada/zero_zilch_nada_test.go | 246 ++++++++++-------- 11 files changed, 297 insertions(+), 350 deletions(-) diff --git a/concepts/zero-values/.meta/config.json b/concepts/zero-values/.meta/config.json index 6a4641833..bac27f7a8 100644 --- a/concepts/zero-values/.meta/config.json +++ b/concepts/zero-values/.meta/config.json @@ -1,5 +1,7 @@ { "blurb": "Learn about zero values.", - "authors": [], + "authors": [ + "sudomateo" + ], "contributors": [] } diff --git a/concepts/zero-values/about.md b/concepts/zero-values/about.md index de5b7765e..ab67b1180 100644 --- a/concepts/zero-values/about.md +++ b/concepts/zero-values/about.md @@ -1,24 +1,24 @@ -# Zero Values +# About -Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. +Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | -| bool | false | -| numeric | 0 | -| string | "" | -| pointer | nil | -| interface | nil | -| channel | nil | -| map | nil | -| slice | nil | -| func | nil | +| boolean | `false` | +| numeric | `0` | +| string | `""` | +| pointer | `nil` | +| function | `nil` | +| interface | `nil` | +| slice | `nil` | +| channel | `nil` | +| map | `nil` | ## Zero Value Construction @@ -27,41 +27,31 @@ The `var` keyword can be used to construct any type to its zero value: ```go func main() { var myBool bool - fmt.Println(myBool) + fmt.Println("Zero value boolean:", myBool) } ``` ```go func main() { - var myMap map[int]int - fmt.Println(myMap) + var mySlice []int + fmt.Println("Zero value slice:", mySlice) } ``` -## Comparing Types to Nil - -Comparing a type whose zero value is not `nil` to `nil` is an error: +When constructing the zero value for a struct type, all of the struct's fields will be set to their zero value: ```go -func main() { - var myString string - - if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) - fmt.Println(myString) - } +type Person struct { + Name string + Age int } -``` -However, comparing a type whose zero value is `nil` to `nil` is acceptable: - -```go func main() { - var mySlice []int - - if mySlice != nil { - fmt.Println(mySlice) - } + var myPerson Person + fmt.Println("Zero value Person:", myPerson) } ``` -[zero_values]: https://golang.org/ref/spec#The_zero_value +## Related Concepts + +- [concept:go/nil]() diff --git a/concepts/zero-values/introduction.md b/concepts/zero-values/introduction.md index e3667805e..5726a9ba8 100644 --- a/concepts/zero-values/introduction.md +++ b/concepts/zero-values/introduction.md @@ -1,67 +1,21 @@ # Introduction -Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. +Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | -| bool | false | -| numeric | 0 | -| string | "" | -| pointer | nil | -| interface | nil | -| channel | nil | -| map | nil | -| slice | nil | -| func | nil | - -## Zero Value Construction - -The `var` keyword can be used to construct any type to its zero value: - -```go -func main() { - var myBool bool - fmt.Println(myBool) -} -``` - -```go -func main() { - var myMap map[int]int - fmt.Println(myMap) -} -``` - -## Comparing Types to Nil - -Comparing a type whose zero value is not `nil` to `nil` is an error: - -```go -func main() { - var myString string - - if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) - fmt.Println(myString) - } -} -``` - -However, comparing a type whose zero value is `nil` to `nil` is acceptable: - -```go -func main() { - var mySlice []int - - if mySlice != nil { - fmt.Println(mySlice) - } -} -``` - -[zero_values]: https://golang.org/ref/spec#The_zero_value +| boolean | `false` | +| numeric | `0` | +| string | `""` | +| pointer | `nil` | +| function | `nil` | +| interface | `nil` | +| slice | `nil` | +| channel | `nil` | +| map | `nil` | diff --git a/concepts/zero-values/links.json b/concepts/zero-values/links.json index 035ef025c..fe51488c7 100644 --- a/concepts/zero-values/links.json +++ b/concepts/zero-values/links.json @@ -1,6 +1 @@ -[ - { - "url": "https://golang.org/ref/spec#The_zero_value", - "description": "zero_values" - } -] +[] diff --git a/exercises/concept/zero-zilch-nada/.docs/hints.md b/exercises/concept/zero-zilch-nada/.docs/hints.md index 11fdaf752..77a3a71f1 100644 --- a/exercises/concept/zero-zilch-nada/.docs/hints.md +++ b/exercises/concept/zero-zilch-nada/.docs/hints.md @@ -4,44 +4,44 @@ - To [return][returns] a value from a function in Go, use the keyword `return` followed by the value: ```go - func myFunc() int { - return 7 + func myFunc() bool { + return true } ``` -## 1. Return a bool set to its zero value +## 1. Determine if a boolean is set to its zero value - The zero value for the bool type is `false`. -## 2. Return an int set to its zero value +## 2. Determine if an integer is set to its zero value - The zero value for numeric types is `0`. -## 3. Return a string set to its zero value +## 3. Determine if a string is set to its zero value - The zero value for the string type is the empty string `""`. -## 4. Return a func set to its zero value +## 4. Determine if a pointer is set to its zero value - The zero value for the func type is `nil`. -## 5. Return a pointer set to its zero value +## 5. Determine if a function is set to its zero value - The zero value for the pointer type is `nil`. -## 6. Return a map set to its zero value +## 6. Determine if an interface is set to its zero value - The zero value for the map type is `nil`. -## 7. Return a slice set to its zero value +## 7. Determine if a slice is set to its zero value - The zero value for the slice type is `nil`. -## 8. Return a channel set to its zero value +## 8. Determine if a channel is set to its zero value - The zero value for the channel type is `nil`. -## 9. Return an interface set to its zero value +## 9. Determine if a map is set to its zero value - The zero value for the interface type is `nil`. diff --git a/exercises/concept/zero-zilch-nada/.docs/instructions.md b/exercises/concept/zero-zilch-nada/.docs/instructions.md index be33181a2..0f136c1bc 100644 --- a/exercises/concept/zero-zilch-nada/.docs/instructions.md +++ b/exercises/concept/zero-zilch-nada/.docs/instructions.md @@ -1,41 +1,39 @@ # Instructions -In this exercise, we will write some functions that return the zero value for -Go's types. You may not have seen some of the types yet. They will be -introduced in detail in later exercises. +In this exercise, we will write some functions that determine whether or not the function parameter is the zero value for its respective type. -## 1. Return a bool set to its zero value +## 1. Determine if a boolean is set to its zero value -Adjust the `ZeroBool` function to return the zero value for a bool. +Adjust the `IsZeroBool` function to return `true` if the passed in `bool` is set to its zero value and `false` if it is not. -## 2. Return an int set to its zero value +## 2. Determine if an integer is set to its zero value -Adjust the `ZeroInt` function to return the zero value for an int. +Adjust the `IsZeroInt` function to return `true` if the passed in `int` is set to its zero value and `false` if it is not. -## 3. Return a string set to its zero value +## 3. Determine if a string is set to its zero value -Adjust the `ZeroString` function to return the zero value for a string. +Adjust the `IsZeroString` function to return `true` if the passed in `string` is set to its zero value and `false` if it is not. -## 4. Return a func set to its zero value +## 4. Determine if a pointer is set to its zero value -Adjust the `ZeroFunc` function to return the zero value for a func. +Adjust the `IsZeroPointer` function to return `true` if the passed in pointer is set to its zero value and `false` if it is not. -## 5. Return a pointer set to its zero value +## 5. Determine if a function is set to its zero value -Adjust the `ZeroPointer` function to return the zero value for a pointer. +Adjust the `IsZeroFunc` function to return `true` if the passed in `func` is set to its zero value and `false` if it is not. -## 6. Return a map set to its zero value +## 6. Determine if an interface is set to its zero value -Adjust the `ZeroMap` function to return the zero value for a map. +Adjust the `IsZeroInterface` function to return `true` if the passed in interface is set to its zero value and `false` if it is not. -## 7. Return a slice set to its zero value +## 7. Determine if a slice is set to its zero value -Adjust the `ZeroSlice` function to return the zero value for a slice. +Adjust the `IsZeroSlice` function to return `true` if the passed in slice is set to its zero value and `false` if it is not. -## 8. Return a channel set to its zero value +## 8. Determine if a channel is set to its zero value -Adjust the `ZeroChannel` function to return the zero value for a channel. +Adjust the `IsZeroChannel` function to return `true` if the passed in channel is set to its zero value and `false` if it is not. -## 9. Return an interface set to its zero value +## 9. Determine if a map is set to its zero value -Adjust the `ZeroInterface` function to return the zero value for an interface. +Adjust the `IsZeroMap` function to return `true` if the passed in map is set to its zero value and `false` if it is not. diff --git a/exercises/concept/zero-zilch-nada/.docs/introduction.md b/exercises/concept/zero-zilch-nada/.docs/introduction.md index e3667805e..5726a9ba8 100644 --- a/exercises/concept/zero-zilch-nada/.docs/introduction.md +++ b/exercises/concept/zero-zilch-nada/.docs/introduction.md @@ -1,67 +1,21 @@ # Introduction -Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. +Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | -| bool | false | -| numeric | 0 | -| string | "" | -| pointer | nil | -| interface | nil | -| channel | nil | -| map | nil | -| slice | nil | -| func | nil | - -## Zero Value Construction - -The `var` keyword can be used to construct any type to its zero value: - -```go -func main() { - var myBool bool - fmt.Println(myBool) -} -``` - -```go -func main() { - var myMap map[int]int - fmt.Println(myMap) -} -``` - -## Comparing Types to Nil - -Comparing a type whose zero value is not `nil` to `nil` is an error: - -```go -func main() { - var myString string - - if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) - fmt.Println(myString) - } -} -``` - -However, comparing a type whose zero value is `nil` to `nil` is acceptable: - -```go -func main() { - var mySlice []int - - if mySlice != nil { - fmt.Println(mySlice) - } -} -``` - -[zero_values]: https://golang.org/ref/spec#The_zero_value +| boolean | `false` | +| numeric | `0` | +| string | `""` | +| pointer | `nil` | +| function | `nil` | +| interface | `nil` | +| slice | `nil` | +| channel | `nil` | +| map | `nil` | diff --git a/exercises/concept/zero-zilch-nada/.meta/design.md b/exercises/concept/zero-zilch-nada/.meta/design.md index 248aa7e58..1451d2ba6 100644 --- a/exercises/concept/zero-zilch-nada/.meta/design.md +++ b/exercises/concept/zero-zilch-nada/.meta/design.md @@ -13,7 +13,6 @@ The goal of this exercise is to teach the student about the zero value of Go's t ## Out of scope - Error checking. -- `nil` checking. - Usage of the above-mentioned types. ## Concepts diff --git a/exercises/concept/zero-zilch-nada/.meta/exemplar.go b/exercises/concept/zero-zilch-nada/.meta/exemplar.go index 361ef081a..0c0b4b3b5 100644 --- a/exercises/concept/zero-zilch-nada/.meta/exemplar.go +++ b/exercises/concept/zero-zilch-nada/.meta/exemplar.go @@ -1,46 +1,73 @@ package zero -// ZeroBool returns a bool set to its zero value. -func ZeroBool() bool { +// IsZeroBool determines if a given bool is set to its zero value. +func IsZeroBool(b bool) bool { + if b == false { + return true + } return false } -// ZeroInt returns an int set to its zero value. -func ZeroInt() int { - return 0 +// IsZeroInt determines if a given int is set to its zero value. +func IsZeroInt(i int) bool { + if i == 0 { + return true + } + return false } -// ZeroString returns a string set to its zero value. -func ZeroString() string { - return "" +// IsZeroString determines if a given string is set to its zero value. +func IsZeroString(s string) bool { + if s == "" { + return true + } + return false } -// ZeroFunc returns a func set to its zero value. -func ZeroFunc() func() { - return nil +// IsZeroFunc determines if a given function is set to its zero value. +func IsZeroFunc(f func()) bool { + if f == nil { + return true + } + return false } -// ZeroPointer returns a pointer set to its zero value. -func ZeroPointer() *int { - return nil +// IsZeroPointer determines if a given pointer is set to its zero value. +func IsZeroPointer(i *int) bool { + if i == nil { + return true + } + return false } -// ZeroMap returns a map set to its zero value. -func ZeroMap() map[int]int { - return nil +// IsZeroMap determines if a given map is set to its zero value. +func IsZeroMap(m map[string]int) bool { + if m == nil { + return true + } + return false } -// ZeroSlice returns a slice set to its zero value. -func ZeroSlice() []int { - return nil +// IsZeroSlice determines if a given slice is set to its zero value. +func IsZeroSlice(i []int) bool { + if i == nil { + return true + } + return false } -// ZeroChannel returns a channel set to its zero value. -func ZeroChannel() chan int { - return nil +// IsZeroChannel determines if a given channel is set to its zero value. +func IsZeroChannel(c chan int) bool { + if c == nil { + return true + } + return false } -// ZeroInterface returns an interface set to its zero value. -func ZeroInterface() interface{} { - return nil +// IsZeroInterface determines if a given interface is set to its zero value. +func IsZeroInterface(i interface{}) bool { + if i == nil { + return true + } + return false } diff --git a/exercises/concept/zero-zilch-nada/zero_zilch_nada.go b/exercises/concept/zero-zilch-nada/zero_zilch_nada.go index 09305e805..9324b755e 100644 --- a/exercises/concept/zero-zilch-nada/zero_zilch_nada.go +++ b/exercises/concept/zero-zilch-nada/zero_zilch_nada.go @@ -1,46 +1,46 @@ package zero -// ZeroBool returns a bool set to its zero value. -func ZeroBool() bool { - panic("please implement the ZeroBool function") +// IsZeroBool determines if a given bool is set to its zero value. +func IsZeroBool(b bool) bool { + panic("please implement the IsZeroBool function") } -// ZeroInt returns an int set to its zero value. -func ZeroInt() int { - panic("please implement the ZeroInt function") +// IsZeroInt determines if a given int is set to its zero value. +func IsZeroInt(i int) bool { + panic("please implement the IsZeroInt function") } -// ZeroString returns a string set to its zero value. -func ZeroString() string { - panic("please implement the ZeroString function") +// IsZeroString determines if a given string is set to its zero value. +func IsZeroString(s string) bool { + panic("please implement the IsZeroString function") } -// ZeroFunc returns a func set to its zero value. -func ZeroFunc() func() { - panic("please implement the ZeroFunc function") +// IsZeroPointer determines if a given pointer is set to its zero value. +func IsZeroPointer(i *int) bool { + panic("please implement the IsZeroPointer function") } -// ZeroPointer returns a pointer set to its zero value. -func ZeroPointer() *int { - panic("please implement the ZeroPointer function") +// IsZeroFunc determines if a given function is set to its zero value. +func IsZeroFunc(f func()) bool { + panic("please implement the IsZeroFunc function") } -// ZeroMap returns a map set to its zero value. -func ZeroMap() map[int]int { - panic("please implement the ZeroMap function") +// IsZeroInterface determines if a given interface is set to its zero value. +func IsZeroInterface(i interface{}) bool { + panic("please implement the IsZeroInterface function") } -// ZeroSlice returns a slice set to its zero value. -func ZeroSlice() []int { - panic("please implement the ZeroSlice function") +// IsZeroSlice determines if a given slice is set to its zero value. +func IsZeroSlice(i []int) bool { + panic("please implement the IsZeroSlice function") } -// ZeroChannel returns a channel set to its zero value. -func ZeroChannel() chan int { - panic("please implement the ZeroChannel function") +// IsZeroChannel determines if a given channel is set to its zero value. +func IsZeroChannel(c chan int) bool { + panic("please implement the IsZeroChannel function") } -// ZeroInterface returns an interface set to its zero value. -func ZeroInterface() interface{} { - panic("please implement the ZeroInterface function") +// IsZeroMap determines if a given map is set to its zero value. +func IsZeroMap(map[string]int) bool { + panic("please implement the IsZeroMap function") } diff --git a/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go b/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go index 430e1270f..f67347a8d 100644 --- a/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go +++ b/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go @@ -1,141 +1,169 @@ package zero import ( - "reflect" "testing" ) -func TestZeroInterface(t *testing.T) { - test := struct { - name string - want interface{} +func TestIsZeroBool(t *testing.T) { + tests := []struct { + name string + value bool + want bool }{ - "ZeroInterface", - nil, - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroInterface(); got != test.want { - t.Errorf("ZeroInterface() = %v, want %v", got, test.want) - } - }) + {"ZeroBool", false, true}, + {"NonZeroBool", true, false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroBool(test.value); got != test.want { + t.Errorf("IsZeroBool() = %t, want %t", got, test.want) + } + }) + } } -func TestZeroMap(t *testing.T) { - test := struct { - name string - want map[int]int +func TestIsZeroInt(t *testing.T) { + tests := []struct { + name string + value int + want bool }{ - "ZeroMap", - nil, - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroMap(); got != nil { - t.Errorf("ZeroMap() = %v, want %v", got, test.want) - } - }) + {"ZeroInt", 0, true}, + {"NonZeroInt", 42, false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroInt(test.value); got != test.want { + t.Errorf("IsZeroInt() = %t, want %t", got, test.want) + } + }) + } } -func TestZeroSlice(t *testing.T) { - test := struct { - name string - want []int +func TestIsZeroString(t *testing.T) { + tests := []struct { + name string + value string + want bool }{ - "ZeroSlice", - nil, - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroSlice(); got != nil { - t.Errorf("ZeroSlice() = %p, want %p", got, test.want) - } - }) + {"ZeroString", "", true}, + {"NonZeroString", "exercism", false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroString(test.value); got != test.want { + t.Errorf("IsZeroString() = %t, want %t", got, test.want) + } + }) + } } -func TestZeroString(t *testing.T) { - test := struct { - name string - want string +func TestIsZeroPointer(t *testing.T) { + i := 42 + + tests := []struct { + name string + value *int + want bool }{ - "ZeroString", - "", - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroString(); got != test.want { - t.Errorf("ZeroString() = %s, want %s", got, test.want) - } - }) + {"ZeroPointer", nil, true}, + {"NonZeroPointer", &i, false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroPointer(test.value); got != test.want { + t.Errorf("IsZeroPointer() = %t, want %t", got, test.want) + } + }) + } } -func TestZeroChannel(t *testing.T) { - test := struct { - name string - want chan int +func TestIsZeroFunc(t *testing.T) { + tests := []struct { + name string + value func() + want bool }{ - "ZeroChannel", - nil, - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroChannel(); got != test.want { - t.Errorf("ZeroChannel() = %v, want %v", got, test.want) - } - }) + {"ZeroFunc", nil, true}, + {"NonZeroFunc", func() {}, false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroFunc(test.value); got != test.want { + t.Errorf("IsZeroFunc() = %t, want %t", got, test.want) + } + }) + } } -func TestZeroPointer(t *testing.T) { - test := struct { - name string - want *int +func TestIsZeroInterface(t *testing.T) { + tests := []struct { + name string + value interface{} + want bool }{ - "ZeroPointer", - nil, - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroPointer(); got != test.want { - t.Errorf("ZeroPointer() = %v, want %v", got, test.want) - } - }) + {"ZeroInterface", nil, true}, + {"NonZeroInterface", "exercism", false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroInterface(test.value); got != test.want { + t.Errorf("IsZeroInterface() = %t, want %t", got, test.want) + } + }) + } } -func TestZeroBool(t *testing.T) { - test := struct { - name string - want bool +func TestIsZeroSlice(t *testing.T) { + tests := []struct { + name string + value []int + want bool }{ - "ZeroBool", - false, - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroBool(); got != test.want { - t.Errorf("ZeroBool() = %t, want %t", got, test.want) - } - }) + {"ZeroSlice", nil, true}, + {"NonZeroSlice", []int{}, false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroSlice(test.value); got != test.want { + t.Errorf("IsZeroSlice() = %t, want %t", got, test.want) + } + }) + } } -func TestZeroFunc(t *testing.T) { - test := struct { - name string - want func() +func TestIsZeroChannel(t *testing.T) { + tests := []struct { + name string + value chan int + want bool }{ - "ZeroFunc", - nil, - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroFunc(); !reflect.DeepEqual(got, test.want) { - t.Errorf("ZeroFunc() = %p, want nil", got) - } - }) + {"ZeroChannel", nil, true}, + {"NonZeroChannel", make(chan int), false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroChannel(test.value); got != test.want { + t.Errorf("IsZeroChannel() = %t, want %t", got, test.want) + } + }) + } } -func TestZeroInt(t *testing.T) { - test := struct { - name string - want int +func TestIsZeroMap(t *testing.T) { + tests := []struct { + name string + value map[string]int + want bool }{ - "ZeroInt", - 0, - } - t.Run(test.name, func(t *testing.T) { - if got := ZeroInt(); got != test.want { - t.Errorf("ZeroInt() = %d, want %d", got, test.want) - } - }) + {"ZeroMap", nil, true}, + {"NonZeroMap", map[string]int{}, false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsZeroMap(test.value); got != test.want { + t.Errorf("IsZeroMap() = %t, want %t", got, test.want) + } + }) + } } From bd0177639bb8030e079b6d791b15796c321170a1 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Thu, 16 Sep 2021 01:19:37 -0400 Subject: [PATCH 05/16] Add missing period --- concepts/zero-values/about.md | 2 +- concepts/zero-values/introduction.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/concepts/zero-values/about.md b/concepts/zero-values/about.md index ab67b1180..36a00fe27 100644 --- a/concepts/zero-values/about.md +++ b/concepts/zero-values/about.md @@ -4,7 +4,7 @@ Go does not have a concept of empty, null, or undefined for variable values. Var The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. The following table details the zero value for Go's types. diff --git a/concepts/zero-values/introduction.md b/concepts/zero-values/introduction.md index 5726a9ba8..a1c2c30f1 100644 --- a/concepts/zero-values/introduction.md +++ b/concepts/zero-values/introduction.md @@ -4,7 +4,7 @@ Go does not have a concept of empty, null, or undefined for variable values. Var The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. The following table details the zero value for Go's types. From 2d1842f0405fc9022186b042f5c0640ac802d4af Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Thu, 16 Sep 2021 01:19:55 -0400 Subject: [PATCH 06/16] Update nil concept --- concepts/nil/.meta/config.json | 4 +- concepts/nil/about.md | 42 ++++++--------------- concepts/nil/introduction.md | 68 ++++++---------------------------- concepts/nil/links.json | 7 +--- 4 files changed, 26 insertions(+), 95 deletions(-) diff --git a/concepts/nil/.meta/config.json b/concepts/nil/.meta/config.json index ba4220247..94fef890f 100644 --- a/concepts/nil/.meta/config.json +++ b/concepts/nil/.meta/config.json @@ -1,5 +1,7 @@ { "blurb": "Learn about nil.", - "authors": [], + "authors": [ + "sudomateo" + ], "contributors": [] } diff --git a/concepts/nil/about.md b/concepts/nil/about.md index e3667805e..6de04464a 100644 --- a/concepts/nil/about.md +++ b/concepts/nil/about.md @@ -1,42 +1,24 @@ # Introduction -Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. +Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | -| bool | false | -| numeric | 0 | -| string | "" | -| pointer | nil | -| interface | nil | -| channel | nil | -| map | nil | -| slice | nil | -| func | nil | - -## Zero Value Construction - -The `var` keyword can be used to construct any type to its zero value: - -```go -func main() { - var myBool bool - fmt.Println(myBool) -} -``` - -```go -func main() { - var myMap map[int]int - fmt.Println(myMap) -} -``` +| boolean | `false` | +| numeric | `0` | +| string | `""` | +| pointer | `nil` | +| function | `nil` | +| interface | `nil` | +| slice | `nil` | +| channel | `nil` | +| map | `nil` | ## Comparing Types to Nil @@ -63,5 +45,3 @@ func main() { } } ``` - -[zero_values]: https://golang.org/ref/spec#The_zero_value diff --git a/concepts/nil/introduction.md b/concepts/nil/introduction.md index e3667805e..a1c2c30f1 100644 --- a/concepts/nil/introduction.md +++ b/concepts/nil/introduction.md @@ -1,67 +1,21 @@ # Introduction -Go does not have a concept of undefined for variable values. Variables declared without an explicit initial value default to the [zero value][zero_values] for their respective type. +Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, interfaces, channels, maps, slices, and functions. +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. The following table details the zero value for Go's types. | Type | Zero Value | | --------- | ---------- | -| bool | false | -| numeric | 0 | -| string | "" | -| pointer | nil | -| interface | nil | -| channel | nil | -| map | nil | -| slice | nil | -| func | nil | - -## Zero Value Construction - -The `var` keyword can be used to construct any type to its zero value: - -```go -func main() { - var myBool bool - fmt.Println(myBool) -} -``` - -```go -func main() { - var myMap map[int]int - fmt.Println(myMap) -} -``` - -## Comparing Types to Nil - -Comparing a type whose zero value is not `nil` to `nil` is an error: - -```go -func main() { - var myString string - - if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) - fmt.Println(myString) - } -} -``` - -However, comparing a type whose zero value is `nil` to `nil` is acceptable: - -```go -func main() { - var mySlice []int - - if mySlice != nil { - fmt.Println(mySlice) - } -} -``` - -[zero_values]: https://golang.org/ref/spec#The_zero_value +| boolean | `false` | +| numeric | `0` | +| string | `""` | +| pointer | `nil` | +| function | `nil` | +| interface | `nil` | +| slice | `nil` | +| channel | `nil` | +| map | `nil` | diff --git a/concepts/nil/links.json b/concepts/nil/links.json index 035ef025c..fe51488c7 100644 --- a/concepts/nil/links.json +++ b/concepts/nil/links.json @@ -1,6 +1 @@ -[ - { - "url": "https://golang.org/ref/spec#The_zero_value", - "description": "zero_values" - } -] +[] From e69b27a6751122744a17c5ffb1d0560a48d20e00 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Thu, 16 Sep 2021 16:03:46 -0400 Subject: [PATCH 07/16] Add census exercise --- config.json | 4 +- exercises/concept/census/.docs/hints.md | 20 +++ .../concept/census/.docs/instructions.md | 98 ++++++++++ .../.docs/introduction.md | 2 +- .../.meta/config.json | 8 +- .../.meta/design.md | 0 exercises/concept/census/.meta/exemplar.go | 57 ++++++ exercises/concept/census/census.go | 28 +++ exercises/concept/census/census_test.go | 143 +++++++++++++++ exercises/concept/census/go.mod | 3 + .../concept/zero-zilch-nada/.docs/hints.md | 48 ----- .../zero-zilch-nada/.docs/instructions.md | 39 ---- .../concept/zero-zilch-nada/.meta/exemplar.go | 73 -------- exercises/concept/zero-zilch-nada/go.mod | 3 - .../zero-zilch-nada/zero_zilch_nada.go | 46 ----- .../zero-zilch-nada/zero_zilch_nada_test.go | 169 ------------------ 16 files changed, 356 insertions(+), 385 deletions(-) create mode 100644 exercises/concept/census/.docs/hints.md create mode 100644 exercises/concept/census/.docs/instructions.md rename exercises/concept/{zero-zilch-nada => census}/.docs/introduction.md (97%) rename exercises/concept/{zero-zilch-nada => census}/.meta/config.json (70%) rename exercises/concept/{zero-zilch-nada => census}/.meta/design.md (100%) create mode 100644 exercises/concept/census/.meta/exemplar.go create mode 100644 exercises/concept/census/census.go create mode 100644 exercises/concept/census/census_test.go create mode 100644 exercises/concept/census/go.mod delete mode 100644 exercises/concept/zero-zilch-nada/.docs/hints.md delete mode 100644 exercises/concept/zero-zilch-nada/.docs/instructions.md delete mode 100644 exercises/concept/zero-zilch-nada/.meta/exemplar.go delete mode 100644 exercises/concept/zero-zilch-nada/go.mod delete mode 100644 exercises/concept/zero-zilch-nada/zero_zilch_nada.go delete mode 100644 exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go diff --git a/config.json b/config.json index 3bf596cce..c25b50952 100644 --- a/config.json +++ b/config.json @@ -228,8 +228,8 @@ "status": "beta" }, { - "name": "Zero, Zilch, Nada", - "slug": "zero-zilch-nada", + "name": "Census", + "slug": "census", "uuid": "fa4735f8-4d8a-4fb1-85ed-9cf03e9f7b7a", "concepts": [ "nil", diff --git a/exercises/concept/census/.docs/hints.md b/exercises/concept/census/.docs/hints.md new file mode 100644 index 000000000..0c82c845e --- /dev/null +++ b/exercises/concept/census/.docs/hints.md @@ -0,0 +1,20 @@ +# Hints + +## 1. Create a new resident + +- Revisit the [structs concept][concept-structs] for information on how to create structs. + +## 2. Validate resident information + +- The zero value for a string is `""`. +- The zero value for a map is `nil`. +- Revisit the [maps concept][concept-maps] for information on how to determine if a map key exists. + +## 3. Delete resident information + +- A resident is considered deleted when all of their fields are set to their zero value. +- Revisit the [zero-values concept][concept-zero-values] for the zero value for each Go type. + +## 4. Count the residents + +- Revisit the [range-iteration concept][concept-range-iteration] for information on how to range over a slice. diff --git a/exercises/concept/census/.docs/instructions.md b/exercises/concept/census/.docs/instructions.md new file mode 100644 index 000000000..152c2d597 --- /dev/null +++ b/exercises/concept/census/.docs/instructions.md @@ -0,0 +1,98 @@ +# Instructions + +It is your job to prepare the city's IT system for an upcoming census. Specifically, you are responsible for the program that will injest the data from the census workers. + +The program must be able to create a new resident in the system when given a resident's information. Additionally, you will create functions that ensure the required information is present in the resident's data and delete a resident's data. Lastly, you will count the residents to provide an accurate census count. + +## 1. Create a new resident + +When a census worker collects a resident's information, they need register that resident by entering their name, age, and address into the system. + +Implement the function `NewResident` that accepts three arguments: + +- The name of the resident. + +- The age of the resident. + +- The address of the resident. + +The function should return a pointer to a `Resident` struct that holds this information. + +```go +name := "Matthew Sanabria" +age := 29 +address := map[string]string{"street": "Main St.",} + +NewResident(name, age, address) +// => &{Matthew Sanabria 29 map[street:Main St.]} +``` + +## 2. Validate required information + +Residents may be reluctant to provide personal data to census workers. In those cases it's necessary to determine if the resident provided the required information to be counted in the census. + +In order to be counted, a resident must provide a non-zero value for their name and an address that contains a non-zero value for the `street` key. All other information, such as the resident's age, is optional. Implement the `HasRequiredInfo` method that returns a boolean indicating if the resident has provided the required information. + +```go +name := "Matthew Sanabria" +age := 0 +address := make(map[string]string, 0) + +resident := NewResident(name, age, address) + +resident.HasRequiredInfo() +// => false +``` + +## 3. Delete resident information + +Life moves fast and mistakes happen. A resident can move out of the city. A census worker can make mistakes when collecting data. In those cases, it's necessary to have the ability to delete a resident's data so they will not be counted. + +Implement the `Delete` method that sets all of the fields the resident to their zero value. + +```go +name := "Matthew Sanabria" +age := 29 +address := map[string]string{"street": "Main St.",} + +resident := NewResident(name, age, address) + +fmt.Println(resident) +// => &{Matthew Sanabria 29 map[street:Main St.]} + +resident.Delete() + +fmt.Println(resident) +// => &{ 0 map[]} +``` + +## 4. Count the residents + +Now that the system supports census data, it's time to perform the census and count the residents! + +Implement the function `Count` that accepts one argument: + +- A slice of pointers to `Resident` structs. + +The function should return an integer indicating the number of residents that were counted in the census. A resident can only be counted if they provided the required information to the census worker. + +```go +name1 := "Matthew Sanabria" +age1 := 29 +address1 := map[string]string{"street": "Main St.",} + +resident1 := NewResident(name1, age1, address1) + +name2 := "Rob Pike" +age2 := 0 +address2 := make(map[string]string, 0) + +resident2 := NewResident(name2, age2, address2) + +residents := []*Resident{resident1, resident2,} + +Count(residents) +// => 1 +} + +``` diff --git a/exercises/concept/zero-zilch-nada/.docs/introduction.md b/exercises/concept/census/.docs/introduction.md similarity index 97% rename from exercises/concept/zero-zilch-nada/.docs/introduction.md rename to exercises/concept/census/.docs/introduction.md index 5726a9ba8..a1c2c30f1 100644 --- a/exercises/concept/zero-zilch-nada/.docs/introduction.md +++ b/exercises/concept/census/.docs/introduction.md @@ -4,7 +4,7 @@ Go does not have a concept of empty, null, or undefined for variable values. Var The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps +The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. The following table details the zero value for Go's types. diff --git a/exercises/concept/zero-zilch-nada/.meta/config.json b/exercises/concept/census/.meta/config.json similarity index 70% rename from exercises/concept/zero-zilch-nada/.meta/config.json rename to exercises/concept/census/.meta/config.json index a25701d0f..836c95689 100644 --- a/exercises/concept/zero-zilch-nada/.meta/config.json +++ b/exercises/concept/census/.meta/config.json @@ -1,18 +1,18 @@ { "blurb": "Learn about zero values.", "authors": [ - "jamessouth" + "jamessouth", + "sudomateo" ], "contributors": [ - "sudomateo", "tehsphinx" ], "files": { "solution": [ - "zero_zilch_nada.go" + "census.go" ], "test": [ - "zero_zilch_nada_test.go" + "census_test.go" ], "exemplar": [ ".meta/exemplar.go" diff --git a/exercises/concept/zero-zilch-nada/.meta/design.md b/exercises/concept/census/.meta/design.md similarity index 100% rename from exercises/concept/zero-zilch-nada/.meta/design.md rename to exercises/concept/census/.meta/design.md diff --git a/exercises/concept/census/.meta/exemplar.go b/exercises/concept/census/.meta/exemplar.go new file mode 100644 index 000000000..e515883d3 --- /dev/null +++ b/exercises/concept/census/.meta/exemplar.go @@ -0,0 +1,57 @@ +// Packages census simulates a system used to collect census data. +package census + +// Resident represents a resident in this city. +type Resident struct { + Name string + Age int + Address map[string]string +} + +// NewResident registers a new resident in this city. +func NewResident(name string, age int, address map[string]string) *Resident { + return &Resident{ + Name: name, + Age: age, + Address: address, + } +} + +// HasRequiredInfo determines if a given resident has all of the required information. +func (r *Resident) HasRequiredInfo() bool { + if r.Name == "" { + return false + } + + if _, ok := r.Address["street"]; !ok { + return false + } + + if r.Address["street"] == "" { + return false + } + + return true +} + +// Delete deletes a resident's information. +func (r *Resident) Delete() { + r.Name = "" + r.Age = 0 + r.Address = nil +} + +// Count counts all residents that have provided the required information. +func Count(residents []*Resident) int { + var count int + + for _, resident := range residents { + if !resident.HasRequiredInfo() { + continue + } + + count++ + } + + return count +} diff --git a/exercises/concept/census/census.go b/exercises/concept/census/census.go new file mode 100644 index 000000000..93eb242ea --- /dev/null +++ b/exercises/concept/census/census.go @@ -0,0 +1,28 @@ +package census + +// Resident represents a resident in this city. +type Resident struct { + Name string + Age int + Address map[string]string +} + +// NewResident registers a new resident in this city. +func NewResident(name string, age int, address map[string]string) *Resident { + panic("Please implement NewResident.") +} + +// HasRequiredInfo determines if a given resident has all of the required information. +func (r *Resident) HasRequiredInfo() bool { + panic("Please implement HasRequiredInfo.") +} + +// Delete deletes a resident's information. +func (r *Resident) Delete() { + panic("Please implement Delete.") +} + +// Count counts all residents that have provided the required information. +func Count(residents []*Resident) int { + panic("Please implement Count.") +} diff --git a/exercises/concept/census/census_test.go b/exercises/concept/census/census_test.go new file mode 100644 index 000000000..9d66740eb --- /dev/null +++ b/exercises/concept/census/census_test.go @@ -0,0 +1,143 @@ +package census_test + +import ( + "census" + "testing" +) + +// rawCensusData contains the information collected by census workers. +type rawCensusData struct { + name string + age int + address map[string]string + deleted bool +} + +// tests holds the various test cases to test the census package. +var tests = []struct { + name string + rawCensusData []rawCensusData + want int +}{ + { + name: "no_data", + rawCensusData: []rawCensusData{}, + want: 0, + }, + { + name: "all_valid_data", + rawCensusData: []rawCensusData{ + { + name: "Matthew Sanabria", + age: 29, + address: map[string]string{ + "street": "Main St.", + }, + }, + { + name: "Rob Pike", + age: 64, + address: map[string]string{ + "street": "Gopher Ave.", + }, + }, + }, + want: 2, + }, + { + name: "some_valid_data", + rawCensusData: []rawCensusData{ + { + name: "Matthew Sanabria", + age: 29, + address: map[string]string{}, + }, + { + name: "Rob Pike", + age: 0, + address: map[string]string{ + "street": "Gopher Ave.", + }, + }, + }, + want: 1, + }, + { + name: "all_invalid_data", + rawCensusData: []rawCensusData{ + { + name: "", + age: 0, + address: nil, + }, + }, + want: 0, + }, + { + name: "all_deleted", + rawCensusData: []rawCensusData{ + { + name: "Matthew Sanabria", + age: 29, + address: map[string]string{ + "street": "Main St.", + }, + deleted: true, + }, + { + name: "Rob Pike", + age: 64, + address: map[string]string{ + "street": "Gopher Ave.", + }, + deleted: true, + }, + }, + want: 0, + }, + { + name: "some_deleted", + rawCensusData: []rawCensusData{ + { + name: "Matthew Sanabria", + age: 29, + address: map[string]string{ + "street": "Main St.", + }, + }, + { + name: "Rob Pike", + age: 64, + address: map[string]string{ + "street": "Gopher Ave.", + }, + deleted: true, + }, + }, + want: 1, + }, +} + +// TestCensus tests the census package. +func TestCensus(t *testing.T) { + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + residents := make([]*census.Resident, 0, len(test.rawCensusData)) + + for _, censusData := range test.rawCensusData { + resident := census.NewResident(censusData.name, censusData.age, censusData.address) + + if censusData.deleted { + resident.Delete() + } + + residents = append(residents, resident) + } + + if got := census.Count(residents); got != test.want { + t.Errorf("Count() = %d, want %d", got, test.want) + } + }) + } +} diff --git a/exercises/concept/census/go.mod b/exercises/concept/census/go.mod new file mode 100644 index 000000000..c0eef597d --- /dev/null +++ b/exercises/concept/census/go.mod @@ -0,0 +1,3 @@ +module census + +go 1.14 diff --git a/exercises/concept/zero-zilch-nada/.docs/hints.md b/exercises/concept/zero-zilch-nada/.docs/hints.md deleted file mode 100644 index 77a3a71f1..000000000 --- a/exercises/concept/zero-zilch-nada/.docs/hints.md +++ /dev/null @@ -1,48 +0,0 @@ -# Hints - -## General - -- To [return][returns] a value from a function in Go, use the keyword `return` followed by the value: - ```go - func myFunc() bool { - return true - } - ``` - -## 1. Determine if a boolean is set to its zero value - -- The zero value for the bool type is `false`. - -## 2. Determine if an integer is set to its zero value - -- The zero value for numeric types is `0`. - -## 3. Determine if a string is set to its zero value - -- The zero value for the string type is the empty string `""`. - -## 4. Determine if a pointer is set to its zero value - -- The zero value for the func type is `nil`. - -## 5. Determine if a function is set to its zero value - -- The zero value for the pointer type is `nil`. - -## 6. Determine if an interface is set to its zero value - -- The zero value for the map type is `nil`. - -## 7. Determine if a slice is set to its zero value - -- The zero value for the slice type is `nil`. - -## 8. Determine if a channel is set to its zero value - -- The zero value for the channel type is `nil`. - -## 9. Determine if a map is set to its zero value - -- The zero value for the interface type is `nil`. - -[returns]: https://golang.org/ref/spec#Return_statements diff --git a/exercises/concept/zero-zilch-nada/.docs/instructions.md b/exercises/concept/zero-zilch-nada/.docs/instructions.md deleted file mode 100644 index 0f136c1bc..000000000 --- a/exercises/concept/zero-zilch-nada/.docs/instructions.md +++ /dev/null @@ -1,39 +0,0 @@ -# Instructions - -In this exercise, we will write some functions that determine whether or not the function parameter is the zero value for its respective type. - -## 1. Determine if a boolean is set to its zero value - -Adjust the `IsZeroBool` function to return `true` if the passed in `bool` is set to its zero value and `false` if it is not. - -## 2. Determine if an integer is set to its zero value - -Adjust the `IsZeroInt` function to return `true` if the passed in `int` is set to its zero value and `false` if it is not. - -## 3. Determine if a string is set to its zero value - -Adjust the `IsZeroString` function to return `true` if the passed in `string` is set to its zero value and `false` if it is not. - -## 4. Determine if a pointer is set to its zero value - -Adjust the `IsZeroPointer` function to return `true` if the passed in pointer is set to its zero value and `false` if it is not. - -## 5. Determine if a function is set to its zero value - -Adjust the `IsZeroFunc` function to return `true` if the passed in `func` is set to its zero value and `false` if it is not. - -## 6. Determine if an interface is set to its zero value - -Adjust the `IsZeroInterface` function to return `true` if the passed in interface is set to its zero value and `false` if it is not. - -## 7. Determine if a slice is set to its zero value - -Adjust the `IsZeroSlice` function to return `true` if the passed in slice is set to its zero value and `false` if it is not. - -## 8. Determine if a channel is set to its zero value - -Adjust the `IsZeroChannel` function to return `true` if the passed in channel is set to its zero value and `false` if it is not. - -## 9. Determine if a map is set to its zero value - -Adjust the `IsZeroMap` function to return `true` if the passed in map is set to its zero value and `false` if it is not. diff --git a/exercises/concept/zero-zilch-nada/.meta/exemplar.go b/exercises/concept/zero-zilch-nada/.meta/exemplar.go deleted file mode 100644 index 0c0b4b3b5..000000000 --- a/exercises/concept/zero-zilch-nada/.meta/exemplar.go +++ /dev/null @@ -1,73 +0,0 @@ -package zero - -// IsZeroBool determines if a given bool is set to its zero value. -func IsZeroBool(b bool) bool { - if b == false { - return true - } - return false -} - -// IsZeroInt determines if a given int is set to its zero value. -func IsZeroInt(i int) bool { - if i == 0 { - return true - } - return false -} - -// IsZeroString determines if a given string is set to its zero value. -func IsZeroString(s string) bool { - if s == "" { - return true - } - return false -} - -// IsZeroFunc determines if a given function is set to its zero value. -func IsZeroFunc(f func()) bool { - if f == nil { - return true - } - return false -} - -// IsZeroPointer determines if a given pointer is set to its zero value. -func IsZeroPointer(i *int) bool { - if i == nil { - return true - } - return false -} - -// IsZeroMap determines if a given map is set to its zero value. -func IsZeroMap(m map[string]int) bool { - if m == nil { - return true - } - return false -} - -// IsZeroSlice determines if a given slice is set to its zero value. -func IsZeroSlice(i []int) bool { - if i == nil { - return true - } - return false -} - -// IsZeroChannel determines if a given channel is set to its zero value. -func IsZeroChannel(c chan int) bool { - if c == nil { - return true - } - return false -} - -// IsZeroInterface determines if a given interface is set to its zero value. -func IsZeroInterface(i interface{}) bool { - if i == nil { - return true - } - return false -} diff --git a/exercises/concept/zero-zilch-nada/go.mod b/exercises/concept/zero-zilch-nada/go.mod deleted file mode 100644 index 01aeb3f38..000000000 --- a/exercises/concept/zero-zilch-nada/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module zero - -go 1.14 diff --git a/exercises/concept/zero-zilch-nada/zero_zilch_nada.go b/exercises/concept/zero-zilch-nada/zero_zilch_nada.go deleted file mode 100644 index 9324b755e..000000000 --- a/exercises/concept/zero-zilch-nada/zero_zilch_nada.go +++ /dev/null @@ -1,46 +0,0 @@ -package zero - -// IsZeroBool determines if a given bool is set to its zero value. -func IsZeroBool(b bool) bool { - panic("please implement the IsZeroBool function") -} - -// IsZeroInt determines if a given int is set to its zero value. -func IsZeroInt(i int) bool { - panic("please implement the IsZeroInt function") -} - -// IsZeroString determines if a given string is set to its zero value. -func IsZeroString(s string) bool { - panic("please implement the IsZeroString function") -} - -// IsZeroPointer determines if a given pointer is set to its zero value. -func IsZeroPointer(i *int) bool { - panic("please implement the IsZeroPointer function") -} - -// IsZeroFunc determines if a given function is set to its zero value. -func IsZeroFunc(f func()) bool { - panic("please implement the IsZeroFunc function") -} - -// IsZeroInterface determines if a given interface is set to its zero value. -func IsZeroInterface(i interface{}) bool { - panic("please implement the IsZeroInterface function") -} - -// IsZeroSlice determines if a given slice is set to its zero value. -func IsZeroSlice(i []int) bool { - panic("please implement the IsZeroSlice function") -} - -// IsZeroChannel determines if a given channel is set to its zero value. -func IsZeroChannel(c chan int) bool { - panic("please implement the IsZeroChannel function") -} - -// IsZeroMap determines if a given map is set to its zero value. -func IsZeroMap(map[string]int) bool { - panic("please implement the IsZeroMap function") -} diff --git a/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go b/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go deleted file mode 100644 index f67347a8d..000000000 --- a/exercises/concept/zero-zilch-nada/zero_zilch_nada_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package zero - -import ( - "testing" -) - -func TestIsZeroBool(t *testing.T) { - tests := []struct { - name string - value bool - want bool - }{ - {"ZeroBool", false, true}, - {"NonZeroBool", true, false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroBool(test.value); got != test.want { - t.Errorf("IsZeroBool() = %t, want %t", got, test.want) - } - }) - } -} - -func TestIsZeroInt(t *testing.T) { - tests := []struct { - name string - value int - want bool - }{ - {"ZeroInt", 0, true}, - {"NonZeroInt", 42, false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroInt(test.value); got != test.want { - t.Errorf("IsZeroInt() = %t, want %t", got, test.want) - } - }) - } -} - -func TestIsZeroString(t *testing.T) { - tests := []struct { - name string - value string - want bool - }{ - {"ZeroString", "", true}, - {"NonZeroString", "exercism", false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroString(test.value); got != test.want { - t.Errorf("IsZeroString() = %t, want %t", got, test.want) - } - }) - } -} - -func TestIsZeroPointer(t *testing.T) { - i := 42 - - tests := []struct { - name string - value *int - want bool - }{ - {"ZeroPointer", nil, true}, - {"NonZeroPointer", &i, false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroPointer(test.value); got != test.want { - t.Errorf("IsZeroPointer() = %t, want %t", got, test.want) - } - }) - } -} - -func TestIsZeroFunc(t *testing.T) { - tests := []struct { - name string - value func() - want bool - }{ - {"ZeroFunc", nil, true}, - {"NonZeroFunc", func() {}, false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroFunc(test.value); got != test.want { - t.Errorf("IsZeroFunc() = %t, want %t", got, test.want) - } - }) - } -} - -func TestIsZeroInterface(t *testing.T) { - tests := []struct { - name string - value interface{} - want bool - }{ - {"ZeroInterface", nil, true}, - {"NonZeroInterface", "exercism", false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroInterface(test.value); got != test.want { - t.Errorf("IsZeroInterface() = %t, want %t", got, test.want) - } - }) - } -} - -func TestIsZeroSlice(t *testing.T) { - tests := []struct { - name string - value []int - want bool - }{ - {"ZeroSlice", nil, true}, - {"NonZeroSlice", []int{}, false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroSlice(test.value); got != test.want { - t.Errorf("IsZeroSlice() = %t, want %t", got, test.want) - } - }) - } -} - -func TestIsZeroChannel(t *testing.T) { - tests := []struct { - name string - value chan int - want bool - }{ - {"ZeroChannel", nil, true}, - {"NonZeroChannel", make(chan int), false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroChannel(test.value); got != test.want { - t.Errorf("IsZeroChannel() = %t, want %t", got, test.want) - } - }) - } -} - -func TestIsZeroMap(t *testing.T) { - tests := []struct { - name string - value map[string]int - want bool - }{ - {"ZeroMap", nil, true}, - {"NonZeroMap", map[string]int{}, false}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if got := IsZeroMap(test.value); got != test.want { - t.Errorf("IsZeroMap() = %t, want %t", got, test.want) - } - }) - } -} From bdeb46fa6d49635bbedcd24c2257de3b8ba63bff Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Mon, 20 Sep 2021 21:16:08 -0400 Subject: [PATCH 08/16] Implement pull request feedback --- concepts/nil/about.md | 2 +- concepts/nil/introduction.md | 2 +- config.json | 4 +--- exercises/concept/census/.docs/hints.md | 16 ++++++++++++---- exercises/concept/census/.docs/instructions.md | 6 ++---- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/concepts/nil/about.md b/concepts/nil/about.md index 6de04464a..1aa12d57c 100644 --- a/concepts/nil/about.md +++ b/concepts/nil/about.md @@ -2,7 +2,7 @@ Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. -The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. +The zero value for primitive types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. diff --git a/concepts/nil/introduction.md b/concepts/nil/introduction.md index a1c2c30f1..2bdab5641 100644 --- a/concepts/nil/introduction.md +++ b/concepts/nil/introduction.md @@ -2,7 +2,7 @@ Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. -The zero value for primative types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. +The zero value for primitive types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. diff --git a/config.json b/config.json index c25b50952..893facdd4 100644 --- a/config.json +++ b/config.json @@ -235,9 +235,7 @@ "nil", "zero-values" ], - "prerequisites": [ - "maps" - ], + "prerequisites": [ "maps", "structs", "numbers", "strings", "pointers", "booleans", "methods", "slices", "conditionals-if", "nil" ], "status": "beta" } ], diff --git a/exercises/concept/census/.docs/hints.md b/exercises/concept/census/.docs/hints.md index 0c82c845e..cf4496827 100644 --- a/exercises/concept/census/.docs/hints.md +++ b/exercises/concept/census/.docs/hints.md @@ -2,19 +2,27 @@ ## 1. Create a new resident -- Revisit the [structs concept][concept-structs] for information on how to create structs. +- Revisit the structs concept for information on how to create structs. + +[concept:go/structs]() ## 2. Validate resident information - The zero value for a string is `""`. - The zero value for a map is `nil`. -- Revisit the [maps concept][concept-maps] for information on how to determine if a map key exists. +- Revisit the maps concept for information on how to determine if a map key exists. + +[concept:go/maps]() ## 3. Delete resident information - A resident is considered deleted when all of their fields are set to their zero value. -- Revisit the [zero-values concept][concept-zero-values] for the zero value for each Go type. +- Revisit the zero-values concept for the zero value for each Go type. + +[concept:go/zero-values]() ## 4. Count the residents -- Revisit the [range-iteration concept][concept-range-iteration] for information on how to range over a slice. +- Revisit the range-iteration concept for information on how to range over a slice. + +[concept:go/range-iteration]() diff --git a/exercises/concept/census/.docs/instructions.md b/exercises/concept/census/.docs/instructions.md index 152c2d597..1de61ced4 100644 --- a/exercises/concept/census/.docs/instructions.md +++ b/exercises/concept/census/.docs/instructions.md @@ -1,19 +1,17 @@ # Instructions -It is your job to prepare the city's IT system for an upcoming census. Specifically, you are responsible for the program that will injest the data from the census workers. +It is your job to prepare the city's IT system for an upcoming census. Specifically, you are responsible for the program that will process the data from the census workers. The program must be able to create a new resident in the system when given a resident's information. Additionally, you will create functions that ensure the required information is present in the resident's data and delete a resident's data. Lastly, you will count the residents to provide an accurate census count. ## 1. Create a new resident -When a census worker collects a resident's information, they need register that resident by entering their name, age, and address into the system. +When a census worker collects a resident's information, they need to register that resident by entering their name, age, and address into the system. Implement the function `NewResident` that accepts three arguments: - The name of the resident. - - The age of the resident. - - The address of the resident. The function should return a pointer to a `Resident` struct that holds this information. From bac97a161dc34694d5d024ac62eb662aa05afbd3 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Tue, 21 Sep 2021 10:39:44 -0400 Subject: [PATCH 09/16] Use inline linking --- exercises/concept/census/.docs/hints.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/exercises/concept/census/.docs/hints.md b/exercises/concept/census/.docs/hints.md index cf4496827..2dbad4602 100644 --- a/exercises/concept/census/.docs/hints.md +++ b/exercises/concept/census/.docs/hints.md @@ -2,27 +2,19 @@ ## 1. Create a new resident -- Revisit the structs concept for information on how to create structs. - -[concept:go/structs]() +- Revisit the [concept:go/structs]() concept for information on how to create structs. ## 2. Validate resident information - The zero value for a string is `""`. - The zero value for a map is `nil`. -- Revisit the maps concept for information on how to determine if a map key exists. - -[concept:go/maps]() +- Revisit the [concept:go/maps]() concept for information on how to determine if a map key exists. ## 3. Delete resident information - A resident is considered deleted when all of their fields are set to their zero value. -- Revisit the zero-values concept for the zero value for each Go type. - -[concept:go/zero-values]() +- Revisit the [concept:go/zero-values]() concept for the zero value for each Go type. ## 4. Count the residents -- Revisit the range-iteration concept for information on how to range over a slice. - -[concept:go/range-iteration]() +- Revisit the [concept:go/range-iteration]() concept for information on how to range over a slice. From 4db58ed0588ac3a22f2f1512182b09d3df9d6327 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Tue, 21 Sep 2021 15:46:28 -0400 Subject: [PATCH 10/16] Implement pull request feedback --- concepts/nil/about.md | 4 +- concepts/zero-values/links.json | 11 +- config.json | 2 +- .../concept/census/.docs/instructions.md | 12 +- exercises/concept/census/census.go | 37 ++- exercises/concept/census/census_test.go | 275 +++++++++++------- 6 files changed, 221 insertions(+), 120 deletions(-) diff --git a/concepts/nil/about.md b/concepts/nil/about.md index 1aa12d57c..0d5c80f23 100644 --- a/concepts/nil/about.md +++ b/concepts/nil/about.md @@ -20,9 +20,9 @@ The following table details the zero value for Go's types. | channel | `nil` | | map | `nil` | -## Comparing Types to Nil +## Comparing with Nil -Comparing a type whose zero value is not `nil` to `nil` is an error: +If you try to compare a type whose zero value is not `nil` to `nil`, your code will not compile. You will see a compiler error because booleans, numeric types, and strings can never be `nil` in Go. ```go func main() { diff --git a/concepts/zero-values/links.json b/concepts/zero-values/links.json index fe51488c7..27169ee07 100644 --- a/concepts/zero-values/links.json +++ b/concepts/zero-values/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://golang.org/ref/spec#The_zero_value", + "description": "Go language specification about zero value." + }, + { + "url": "https://dave.cheney.net/2013/01/19/what-is-the-zero-value-and-why-is-it-useful", + "description": "What is the zero value, and what is it useful?" + } +] diff --git a/config.json b/config.json index b98749e1e..f6e6de004 100644 --- a/config.json +++ b/config.json @@ -250,7 +250,7 @@ "nil", "zero-values" ], - "prerequisites": [ "maps", "structs", "numbers", "strings", "pointers", "booleans", "methods", "slices", "conditionals-if", "nil" ], + "prerequisites": [ "maps", "structs", "numbers", "strings", "pointers", "booleans", "methods", "slices", "conditionals-if" ], "status": "beta" } ], diff --git a/exercises/concept/census/.docs/instructions.md b/exercises/concept/census/.docs/instructions.md index 1de61ced4..0cab8b3cb 100644 --- a/exercises/concept/census/.docs/instructions.md +++ b/exercises/concept/census/.docs/instructions.md @@ -19,7 +19,7 @@ The function should return a pointer to a `Resident` struct that holds this info ```go name := "Matthew Sanabria" age := 29 -address := map[string]string{"street": "Main St.",} +address := map[string]string{"street": "Main St."} NewResident(name, age, address) // => &{Matthew Sanabria 29 map[street:Main St.]} @@ -34,7 +34,7 @@ In order to be counted, a resident must provide a non-zero value for their name ```go name := "Matthew Sanabria" age := 0 -address := make(map[string]string, 0) +address := make(map[string]string) resident := NewResident(name, age, address) @@ -51,7 +51,7 @@ Implement the `Delete` method that sets all of the fields the resident to their ```go name := "Matthew Sanabria" age := 29 -address := map[string]string{"street": "Main St.",} +address := map[string]string{"street": "Main St."} resident := NewResident(name, age, address) @@ -77,17 +77,17 @@ The function should return an integer indicating the number of residents that we ```go name1 := "Matthew Sanabria" age1 := 29 -address1 := map[string]string{"street": "Main St.",} +address1 := map[string]string{"street": "Main St."} resident1 := NewResident(name1, age1, address1) name2 := "Rob Pike" age2 := 0 -address2 := make(map[string]string, 0) +address2 := make(map[string]string) resident2 := NewResident(name2, age2, address2) -residents := []*Resident{resident1, resident2,} +residents := []*Resident{resident1, resident2} Count(residents) // => 1 diff --git a/exercises/concept/census/census.go b/exercises/concept/census/census.go index 93eb242ea..e515883d3 100644 --- a/exercises/concept/census/census.go +++ b/exercises/concept/census/census.go @@ -1,3 +1,4 @@ +// Packages census simulates a system used to collect census data. package census // Resident represents a resident in this city. @@ -9,20 +10,48 @@ type Resident struct { // NewResident registers a new resident in this city. func NewResident(name string, age int, address map[string]string) *Resident { - panic("Please implement NewResident.") + return &Resident{ + Name: name, + Age: age, + Address: address, + } } // HasRequiredInfo determines if a given resident has all of the required information. func (r *Resident) HasRequiredInfo() bool { - panic("Please implement HasRequiredInfo.") + if r.Name == "" { + return false + } + + if _, ok := r.Address["street"]; !ok { + return false + } + + if r.Address["street"] == "" { + return false + } + + return true } // Delete deletes a resident's information. func (r *Resident) Delete() { - panic("Please implement Delete.") + r.Name = "" + r.Age = 0 + r.Address = nil } // Count counts all residents that have provided the required information. func Count(residents []*Resident) int { - panic("Please implement Count.") + var count int + + for _, resident := range residents { + if !resident.HasRequiredInfo() { + continue + } + + count++ + } + + return count } diff --git a/exercises/concept/census/census_test.go b/exercises/concept/census/census_test.go index 9d66740eb..820f153b0 100644 --- a/exercises/concept/census/census_test.go +++ b/exercises/concept/census/census_test.go @@ -2,141 +2,204 @@ package census_test import ( "census" + "reflect" "testing" ) -// rawCensusData contains the information collected by census workers. -type rawCensusData struct { - name string - age int - address map[string]string - deleted bool -} - -// tests holds the various test cases to test the census package. -var tests = []struct { - name string - rawCensusData []rawCensusData - want int -}{ - { - name: "no_data", - rawCensusData: []rawCensusData{}, - want: 0, - }, - { - name: "all_valid_data", - rawCensusData: []rawCensusData{ - { - name: "Matthew Sanabria", - age: 29, - address: map[string]string{ +// TestNewResident tests the census.NewResident function. +func TestNewResident(t *testing.T) { + tests := []struct { + name string + resident *census.Resident + }{ + { + name: "no data collected", + resident: &census.Resident{}, + }, + { + name: "all data collected", + resident: &census.Resident{ + Name: "Matthew Sanabria", + Age: 29, + Address: map[string]string{ "street": "Main St.", }, }, - { - name: "Rob Pike", - age: 64, - address: map[string]string{ - "street": "Gopher Ave.", - }, - }, }, - want: 2, - }, - { - name: "some_valid_data", - rawCensusData: []rawCensusData{ - { - name: "Matthew Sanabria", - age: 29, - address: map[string]string{}, - }, - { - name: "Rob Pike", - age: 0, - address: map[string]string{ - "street": "Gopher Ave.", + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + resident := census.NewResident(test.resident.Name, test.resident.Age, test.resident.Address) + + if !reflect.DeepEqual(resident, test.resident) { + t.Errorf("NewResident() = %v, want %v", resident, test.resident) + } + }) + } +} + +// TestHasRequiredInfo tests the census.HasRequiredInfo method. +func TestHasRequiredInfo(t *testing.T) { + tests := []struct { + name string + resident *census.Resident + want bool + }{ + { + name: "no data collected", + resident: &census.Resident{}, + want: false, + }, + { + name: "all data collected", + resident: &census.Resident{ + Name: "Matthew Sanabria", + Age: 29, + Address: map[string]string{ + "street": "Main St.", }, }, + want: true, }, - want: 1, - }, - { - name: "all_invalid_data", - rawCensusData: []rawCensusData{ - { - name: "", - age: 0, - address: nil, + { + name: "missing street", + resident: &census.Resident{ + Name: "Rob Pike", + Age: 0, + Address: map[string]string{}, }, + want: false, }, - want: 0, - }, - { - name: "all_deleted", - rawCensusData: []rawCensusData{ - { - name: "Matthew Sanabria", - age: 29, - address: map[string]string{ + { + name: "missing name", + resident: &census.Resident{ + Name: "", + Age: 29, + Address: map[string]string{ "street": "Main St.", }, - deleted: true, - }, - { - name: "Rob Pike", - age: 64, - address: map[string]string{ - "street": "Gopher Ave.", - }, - deleted: true, }, + want: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + if got := test.resident.HasRequiredInfo(); got != test.want { + t.Errorf("resident.HasRequiredInfo() = %t, want %t", got, test.want) + } + }) + } +} + +// TestDelete tests the census.Delete method. +func TestDelete(t *testing.T) { + tests := []struct { + name string + resident *census.Resident + want *census.Resident + }{ + { + name: "no data collected", + resident: &census.Resident{}, + want: &census.Resident{}, }, - want: 0, - }, - { - name: "some_deleted", - rawCensusData: []rawCensusData{ - { - name: "Matthew Sanabria", - age: 29, - address: map[string]string{ + { + name: "all data collected", + resident: &census.Resident{ + Name: "Matthew Sanabria", + Age: 29, + Address: map[string]string{ "street": "Main St.", }, }, - { - name: "Rob Pike", - age: 64, - address: map[string]string{ - "street": "Gopher Ave.", - }, - deleted: true, + want: &census.Resident{}, + }, + { + name: "some data collected", + resident: &census.Resident{ + Name: "Rob Pike", + Age: 0, + Address: map[string]string{}, }, + want: &census.Resident{}, }, - want: 1, - }, -} + } -// TestCensus tests the census package. -func TestCensus(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - residents := make([]*census.Resident, 0, len(test.rawCensusData)) + test.resident.Delete() - for _, censusData := range test.rawCensusData { - resident := census.NewResident(censusData.name, censusData.age, censusData.address) + if test.resident.Name != "" || + test.resident.Age != 0 || + test.resident.Address != nil { + t.Errorf("resident.Delete() = %v, want %v", test.resident, test.want) + } + }) + } +} - if censusData.deleted { - resident.Delete() - } +// TestCount tests the census.Count function. +func TestCount(t *testing.T) { + tests := []struct { + name string + residents []*census.Resident + want int + }{ + { + name: "no data collected", + residents: []*census.Resident{ + {}, + }, + want: 0, + }, + { + name: "all data collected", + residents: []*census.Resident{ + { + Name: "Matthew Sanabria", + Age: 29, + Address: map[string]string{ + "street": "Main St.", + }, + }, + }, + want: 1, + }, + { + name: "some data collected", + residents: []*census.Resident{ + { + Name: "Matthew Sanabria", + Age: 29, + Address: map[string]string{ + "street": "Main St.", + }, + }, + { + Name: "Rob Pike", + Age: 0, + Address: map[string]string{}, + }, + { + Name: "", + Age: 0, + Address: map[string]string{}, + }, + }, + want: 1, + }, + } - residents = append(residents, resident) - } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { - if got := census.Count(residents); got != test.want { - t.Errorf("Count() = %d, want %d", got, test.want) + if got := census.Count(test.residents); got != test.want { + t.Errorf("census.Count() = %d, want %d", got, test.want) } }) } From bccd5a7e004ed0bdbab8f1461b2dcd18be9468e5 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Wed, 22 Sep 2021 00:34:03 -0400 Subject: [PATCH 11/16] Remove nil concept --- concepts/nil/.meta/config.json | 8 ------ concepts/nil/about.md | 47 ---------------------------------- concepts/nil/introduction.md | 21 --------------- concepts/nil/links.json | 1 - config.json | 6 ----- 5 files changed, 83 deletions(-) delete mode 100644 concepts/nil/.meta/config.json delete mode 100644 concepts/nil/about.md delete mode 100644 concepts/nil/introduction.md delete mode 100644 concepts/nil/links.json diff --git a/concepts/nil/.meta/config.json b/concepts/nil/.meta/config.json deleted file mode 100644 index d821e60a9..000000000 --- a/concepts/nil/.meta/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "blurb": "nil is a special value in Go to represent the absence of a value.", - "authors": [ - "ErikSchierboom", - "sudomateo" - ], - "contributors": [] -} diff --git a/concepts/nil/about.md b/concepts/nil/about.md deleted file mode 100644 index 0d5c80f23..000000000 --- a/concepts/nil/about.md +++ /dev/null @@ -1,47 +0,0 @@ -# Introduction - -Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. - -The zero value for primitive types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. - -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. - -The following table details the zero value for Go's types. - -| Type | Zero Value | -| --------- | ---------- | -| boolean | `false` | -| numeric | `0` | -| string | `""` | -| pointer | `nil` | -| function | `nil` | -| interface | `nil` | -| slice | `nil` | -| channel | `nil` | -| map | `nil` | - -## Comparing with Nil - -If you try to compare a type whose zero value is not `nil` to `nil`, your code will not compile. You will see a compiler error because booleans, numeric types, and strings can never be `nil` in Go. - -```go -func main() { - var myString string - - if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) - fmt.Println(myString) - } -} -``` - -However, comparing a type whose zero value is `nil` to `nil` is acceptable: - -```go -func main() { - var mySlice []int - - if mySlice != nil { - fmt.Println(mySlice) - } -} -``` diff --git a/concepts/nil/introduction.md b/concepts/nil/introduction.md deleted file mode 100644 index 2bdab5641..000000000 --- a/concepts/nil/introduction.md +++ /dev/null @@ -1,21 +0,0 @@ -# Introduction - -Go does not have a concept of empty, null, or undefined for variable values. Variables declared without an explicit initial value default to the zero value for their respective type. - -The zero value for primitive types such as booleans, numeric types, and strings are `false`, `0`, and `""`, respectively. - -The identifier `nil`, meaning zero, is the zero value for more complex types such as pointers, functions, interfaces, slices, channels, and maps. - -The following table details the zero value for Go's types. - -| Type | Zero Value | -| --------- | ---------- | -| boolean | `false` | -| numeric | `0` | -| string | `""` | -| pointer | `nil` | -| function | `nil` | -| interface | `nil` | -| slice | `nil` | -| channel | `nil` | -| map | `nil` | diff --git a/concepts/nil/links.json b/concepts/nil/links.json deleted file mode 100644 index fe51488c7..000000000 --- a/concepts/nil/links.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/config.json b/config.json index f6e6de004..c8916b6c0 100644 --- a/config.json +++ b/config.json @@ -247,7 +247,6 @@ "slug": "census", "uuid": "fa4735f8-4d8a-4fb1-85ed-9cf03e9f7b7a", "concepts": [ - "nil", "zero-values" ], "prerequisites": [ "maps", "structs", "numbers", "strings", "pointers", "booleans", "methods", "slices", "conditionals-if" ], @@ -1809,11 +1808,6 @@ "slug": "methods", "uuid": "d25c6e6b-c6d4-40ce-80f9-cecbc5a72254" }, - { - "name": "Nil", - "slug": "nil", - "uuid": "c4d16fac-3e46-41ac-adf8-ce8f3f73f745" - }, { "name": "Numbers", "slug": "numbers", From 48fa1d2f3cf2865e75046488de72bd1f380460ca Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Wed, 22 Sep 2021 00:34:26 -0400 Subject: [PATCH 12/16] Update zero-values concept content --- concepts/zero-values/about.md | 43 +++++++++++++++++++--------- concepts/zero-values/introduction.md | 2 ++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/concepts/zero-values/about.md b/concepts/zero-values/about.md index 36a00fe27..f5fa2d9a4 100644 --- a/concepts/zero-values/about.md +++ b/concepts/zero-values/about.md @@ -20,22 +20,22 @@ The following table details the zero value for Go's types. | channel | `nil` | | map | `nil` | +You may have noticed struct types are absent from the above table. That is because the zero value for a struct type depends on its fields. Structs are set to their zero value when all of its fields are set to their respective zero value. + ## Zero Value Construction The `var` keyword can be used to construct any type to its zero value: ```go -func main() { - var myBool bool - fmt.Println("Zero value boolean:", myBool) -} +var myBool bool +fmt.Printf("Zero value boolean: %#v", myBool) +// Output: Zero value boolean: false ``` ```go -func main() { - var mySlice []int - fmt.Println("Zero value slice:", mySlice) -} +var mySlice []int +fmt.Printf("Zero value slice: %#v", mySlice) +// Output: Zero value slice: []int(nil) ``` When constructing the zero value for a struct type, all of the struct's fields will be set to their zero value: @@ -46,12 +46,29 @@ type Person struct { Age int } -func main() { - var myPerson Person - fmt.Println("Zero value Person:", myPerson) +var myPerson Person +fmt.Printf("Zero value Person: %#v", myPerson) +// Output: Zero value Person: main.Person{Name:"", Age:0} +``` + +## Comparing with Nil + +If you try to compare a type whose zero value is not `nil` to `nil`, your code will not compile. You will see a compiler error because booleans, numeric types, and strings can never be `nil` in Go. + +```go +var myString string + +if myString != nil { // invalid operation: myString != nil (mismatched types string and nil) + fmt.Println("Do some work here.") } ``` -## Related Concepts +However, comparing a type whose zero value is `nil` to `nil` is acceptable: + +```go +var mySlice []int -- [concept:go/nil]() +if mySlice != nil { + fmt.Println("Do some work here.") +} +``` diff --git a/concepts/zero-values/introduction.md b/concepts/zero-values/introduction.md index a1c2c30f1..c5e23e651 100644 --- a/concepts/zero-values/introduction.md +++ b/concepts/zero-values/introduction.md @@ -19,3 +19,5 @@ The following table details the zero value for Go's types. | slice | `nil` | | channel | `nil` | | map | `nil` | + +You may have noticed struct types are absent from the above table. That is because the zero value for a struct type depends on its fields. Structs are set to their zero value when all of its fields are set to their respective zero value. From e6ba9570f83d405d16165d079bc3122c9f66e36a Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Wed, 22 Sep 2021 00:35:00 -0400 Subject: [PATCH 13/16] Update census exercise - Ensure the links in the hints are inline. - Ensure the introduction includes information on struct types. - Restore the exercise code to an unfinished state. - Update the testing code. --- exercises/concept/census/.docs/hints.md | 8 ++--- .../concept/census/.docs/introduction.md | 2 ++ exercises/concept/census/census.go | 36 +++---------------- exercises/concept/census/census_test.go | 5 ++- 4 files changed, 12 insertions(+), 39 deletions(-) diff --git a/exercises/concept/census/.docs/hints.md b/exercises/concept/census/.docs/hints.md index 2dbad4602..1b0c296bc 100644 --- a/exercises/concept/census/.docs/hints.md +++ b/exercises/concept/census/.docs/hints.md @@ -2,19 +2,19 @@ ## 1. Create a new resident -- Revisit the [concept:go/structs]() concept for information on how to create structs. +- Revisit the [struct concept](https://exercism.org/tracks/go/concepts/structs) for information on how to create structs. ## 2. Validate resident information - The zero value for a string is `""`. - The zero value for a map is `nil`. -- Revisit the [concept:go/maps]() concept for information on how to determine if a map key exists. +- Revisit the [maps concept](https://exercism.org/tracks/go/concepts/maps) for information on how to determine if a map key exists. ## 3. Delete resident information - A resident is considered deleted when all of their fields are set to their zero value. -- Revisit the [concept:go/zero-values]() concept for the zero value for each Go type. +- Revisit the [zero values concept](https://exercism.org/tracks/go/concepts/zero-values) for the zero value for each Go type. ## 4. Count the residents -- Revisit the [concept:go/range-iteration]() concept for information on how to range over a slice. +- Revisit the [range iteration concept](https://exercism.org/tracks/go/concepts/range-iteration) for information on how to range over a slice. diff --git a/exercises/concept/census/.docs/introduction.md b/exercises/concept/census/.docs/introduction.md index a1c2c30f1..c5e23e651 100644 --- a/exercises/concept/census/.docs/introduction.md +++ b/exercises/concept/census/.docs/introduction.md @@ -19,3 +19,5 @@ The following table details the zero value for Go's types. | slice | `nil` | | channel | `nil` | | map | `nil` | + +You may have noticed struct types are absent from the above table. That is because the zero value for a struct type depends on its fields. Structs are set to their zero value when all of its fields are set to their respective zero value. diff --git a/exercises/concept/census/census.go b/exercises/concept/census/census.go index e515883d3..df043e6e2 100644 --- a/exercises/concept/census/census.go +++ b/exercises/concept/census/census.go @@ -10,48 +10,20 @@ type Resident struct { // NewResident registers a new resident in this city. func NewResident(name string, age int, address map[string]string) *Resident { - return &Resident{ - Name: name, - Age: age, - Address: address, - } + panic("Please implement NewResident.") } // HasRequiredInfo determines if a given resident has all of the required information. func (r *Resident) HasRequiredInfo() bool { - if r.Name == "" { - return false - } - - if _, ok := r.Address["street"]; !ok { - return false - } - - if r.Address["street"] == "" { - return false - } - - return true + panic("Please implement HasRequiredInfo.") } // Delete deletes a resident's information. func (r *Resident) Delete() { - r.Name = "" - r.Age = 0 - r.Address = nil + panic("Please implement Delete.") } // Count counts all residents that have provided the required information. func Count(residents []*Resident) int { - var count int - - for _, resident := range residents { - if !resident.HasRequiredInfo() { - continue - } - - count++ - } - - return count + panic("Please implement Count.") } diff --git a/exercises/concept/census/census_test.go b/exercises/concept/census/census_test.go index 820f153b0..c4469c6a7 100644 --- a/exercises/concept/census/census_test.go +++ b/exercises/concept/census/census_test.go @@ -1,3 +1,4 @@ +// Package census_test tests the census package. package census_test import ( @@ -134,9 +135,7 @@ func TestDelete(t *testing.T) { test.resident.Delete() - if test.resident.Name != "" || - test.resident.Age != 0 || - test.resident.Address != nil { + if test.resident.Name != "" || test.resident.Age != 0 || test.resident.Address != nil { t.Errorf("resident.Delete() = %v, want %v", test.resident, test.want) } }) From 20b07837b3f97f3867da5827dd6aeaea5fc0afb3 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Wed, 22 Sep 2021 00:38:21 -0400 Subject: [PATCH 14/16] Use relative links instead of absolute links --- exercises/concept/census/.docs/hints.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/concept/census/.docs/hints.md b/exercises/concept/census/.docs/hints.md index 1b0c296bc..8d970a0b2 100644 --- a/exercises/concept/census/.docs/hints.md +++ b/exercises/concept/census/.docs/hints.md @@ -2,19 +2,19 @@ ## 1. Create a new resident -- Revisit the [struct concept](https://exercism.org/tracks/go/concepts/structs) for information on how to create structs. +- Revisit the [struct concept](/tracks/go/concepts/structs) for information on how to create structs. ## 2. Validate resident information - The zero value for a string is `""`. - The zero value for a map is `nil`. -- Revisit the [maps concept](https://exercism.org/tracks/go/concepts/maps) for information on how to determine if a map key exists. +- Revisit the [maps concept](/tracks/go/concepts/maps) for information on how to determine if a map key exists. ## 3. Delete resident information - A resident is considered deleted when all of their fields are set to their zero value. -- Revisit the [zero values concept](https://exercism.org/tracks/go/concepts/zero-values) for the zero value for each Go type. +- Revisit the [zero values concept](/tracks/go/concepts/zero-values) for the zero value for each Go type. ## 4. Count the residents -- Revisit the [range iteration concept](https://exercism.org/tracks/go/concepts/range-iteration) for information on how to range over a slice. +- Revisit the [range iteration concept](/tracks/go/concepts/range-iteration) for information on how to range over a slice. From bd262f7409d5171c8eb46a9bae74edf7cf381f20 Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Wed, 22 Sep 2021 10:54:57 -0400 Subject: [PATCH 15/16] Update prerequisites --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index c8916b6c0..0bf694897 100644 --- a/config.json +++ b/config.json @@ -249,7 +249,7 @@ "concepts": [ "zero-values" ], - "prerequisites": [ "maps", "structs", "numbers", "strings", "pointers", "booleans", "methods", "slices", "conditionals-if" ], + "prerequisites": [ "maps", "structs", "numbers", "string-formatting", "booleans", "methods", "slices", "conditionals-if" ], "status": "beta" } ], From c582e6591c4a3664471aa83cb7913e330747b7fa Mon Sep 17 00:00:00 2001 From: Matthew Sanabria <24284972+sudomateo@users.noreply.github.com> Date: Wed, 22 Sep 2021 10:55:13 -0400 Subject: [PATCH 16/16] Ensure tests run in the same package as exercise --- exercises/concept/census/census_test.go | 59 ++++++++++++------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/exercises/concept/census/census_test.go b/exercises/concept/census/census_test.go index c4469c6a7..e184c454d 100644 --- a/exercises/concept/census/census_test.go +++ b/exercises/concept/census/census_test.go @@ -1,25 +1,24 @@ -// Package census_test tests the census package. -package census_test +// Package census tests the census package. +package census import ( - "census" "reflect" "testing" ) -// TestNewResident tests the census.NewResident function. +// TestNewResident tests the NewResident function. func TestNewResident(t *testing.T) { tests := []struct { name string - resident *census.Resident + resident *Resident }{ { name: "no data collected", - resident: &census.Resident{}, + resident: &Resident{}, }, { name: "all data collected", - resident: &census.Resident{ + resident: &Resident{ Name: "Matthew Sanabria", Age: 29, Address: map[string]string{ @@ -32,7 +31,7 @@ func TestNewResident(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - resident := census.NewResident(test.resident.Name, test.resident.Age, test.resident.Address) + resident := NewResident(test.resident.Name, test.resident.Age, test.resident.Address) if !reflect.DeepEqual(resident, test.resident) { t.Errorf("NewResident() = %v, want %v", resident, test.resident) @@ -41,21 +40,21 @@ func TestNewResident(t *testing.T) { } } -// TestHasRequiredInfo tests the census.HasRequiredInfo method. +// TestHasRequiredInfo tests the Resident.HasRequiredInfo method. func TestHasRequiredInfo(t *testing.T) { tests := []struct { name string - resident *census.Resident + resident *Resident want bool }{ { name: "no data collected", - resident: &census.Resident{}, + resident: &Resident{}, want: false, }, { name: "all data collected", - resident: &census.Resident{ + resident: &Resident{ Name: "Matthew Sanabria", Age: 29, Address: map[string]string{ @@ -66,7 +65,7 @@ func TestHasRequiredInfo(t *testing.T) { }, { name: "missing street", - resident: &census.Resident{ + resident: &Resident{ Name: "Rob Pike", Age: 0, Address: map[string]string{}, @@ -75,7 +74,7 @@ func TestHasRequiredInfo(t *testing.T) { }, { name: "missing name", - resident: &census.Resident{ + resident: &Resident{ Name: "", Age: 29, Address: map[string]string{ @@ -96,37 +95,37 @@ func TestHasRequiredInfo(t *testing.T) { } } -// TestDelete tests the census.Delete method. +// TestDelete tests the Resident.Delete method. func TestDelete(t *testing.T) { tests := []struct { name string - resident *census.Resident - want *census.Resident + resident *Resident + want *Resident }{ { name: "no data collected", - resident: &census.Resident{}, - want: &census.Resident{}, + resident: &Resident{}, + want: &Resident{}, }, { name: "all data collected", - resident: &census.Resident{ + resident: &Resident{ Name: "Matthew Sanabria", Age: 29, Address: map[string]string{ "street": "Main St.", }, }, - want: &census.Resident{}, + want: &Resident{}, }, { name: "some data collected", - resident: &census.Resident{ + resident: &Resident{ Name: "Rob Pike", Age: 0, Address: map[string]string{}, }, - want: &census.Resident{}, + want: &Resident{}, }, } @@ -142,23 +141,23 @@ func TestDelete(t *testing.T) { } } -// TestCount tests the census.Count function. +// TestCount tests the Count function. func TestCount(t *testing.T) { tests := []struct { name string - residents []*census.Resident + residents []*Resident want int }{ { name: "no data collected", - residents: []*census.Resident{ + residents: []*Resident{ {}, }, want: 0, }, { name: "all data collected", - residents: []*census.Resident{ + residents: []*Resident{ { Name: "Matthew Sanabria", Age: 29, @@ -171,7 +170,7 @@ func TestCount(t *testing.T) { }, { name: "some data collected", - residents: []*census.Resident{ + residents: []*Resident{ { Name: "Matthew Sanabria", Age: 29, @@ -197,8 +196,8 @@ func TestCount(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - if got := census.Count(test.residents); got != test.want { - t.Errorf("census.Count() = %d, want %d", got, test.want) + if got := Count(test.residents); got != test.want { + t.Errorf("Count() = %d, want %d", got, test.want) } }) }