Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/meleu/learning-golang
Learning Go with tests, from https://quii.gitbook.io/learn-go-with-tests
https://github.com/meleu/learning-golang
Last synced: 2 days ago
JSON representation
Learning Go with tests, from https://quii.gitbook.io/learn-go-with-tests
- Host: GitHub
- URL: https://github.com/meleu/learning-golang
- Owner: meleu
- Created: 2022-11-23T01:01:27.000Z (about 2 years ago)
- Default Branch: master
- Last Pushed: 2024-06-02T21:55:05.000Z (7 months ago)
- Last Synced: 2024-11-08T06:13:07.727Z (about 2 months ago)
- Language: Go
- Homepage:
- Size: 18.6 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Learning Golang
Following the [Learn Go with tests](https://quii.gitbook.io/learn-go-with-tests/) gitbook.
Here I list some things I learned in each exercise.
## Hello, World
-
### What I learned
#### Golang tooling
Start a new project as a module with:
```bash
mkdir hello
cd hello
go mod init hello
# check if the "go.mod" file was created
```Recommended linter: [GolangCI-Lint](https://golangci-lint.run/). It can be installed with Homebrew or `asdf` (I used `asdf`).
Useful config to be used in VSCode:
```json
{
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--fast"],
"go.coverOnSave": true,
"go.coverageDecorator": {
"type": "gutter",
"coveredHighlightColor": "rgba(64,128,128,0.5)",
"uncoveredHighlightColor": "rgba(128,64,64,0.25)",
"coveredGutterStyle": "blockgreen",
"uncoveredGutterStyle": "slashred"
}
}
```Awesome tool to rerun tests on file change: [watchexec](https://github.com/watchexec/watchexec). Example of usage:
```bash
# run 'go test' when a change happens on a file ending with .go
watchexec -e go -- go test -v
```Local documentation:
```bash
# installing local documentation
go install golang.org/x/tools/cmd/godoc@latest# NOTE: sometimes godoc won't be in your path.
# in my case it went to `~/.asdf/` structure and I created an alias:
alias godoc=$(find $HOME/.asdf/installs/golang -type f -path '*packages/bin/godoc')# now you can launch the local documentation server
godoc -http :8000
```#### Golang basics
- a program have a `main` package defined with a `main` func inside.
- `func` defines a function with a name and a body (aka block)
- blocks are defined with `{`curly braces`}`
- `import "fmt"` is necessary to use `fmt.Println`
- `if` works like other programming languages, without `(`parenthesis`)`
- variables are ~~assigned~~ declared like this: `varName := value`
- I [researched](https://stackoverflow.com/a/36513229/6354514) and realized that
- `:=` for [short variable declarations](https://go.dev/ref/spec#Short_variable_declarations) (with type inference)
- `=` for [variable declarations](https://go.dev/ref/spec#Variable_declarations) and [assignments](https://go.dev/ref/spec#Assignment_statements).
- constants are defined like `const myConst = "My String"`
- `PublicFunctions` start with a capital letter and `privateFunctions` start with a lowercase.
- `func greetingPrefix(language string) (prefix string)` creates a **named return value**
- creates a variable called `prefix` in the function
- it will be assigned the "zero" value. In this case (`string`): `""`
- example (also showing a `switch` statement):```go
func greetingPrefix(language string) (prefix string) {
switch language {
case spanish:
prefix = spanishHelloPrefix
case french:
prefix = frenchHelloPrefix
case portuguese:
prefix = portugueseHelloPrefix
default:
prefix = englishHelloPrefix
}
return
}
```- example of grouping constants:
```go
const (
spanish = "Spanish"
french = "French"
portuguese = "Portuguese"englishHelloPrefix = "Hello, "
spanishHelloPrefix = "Hola, "
frenchHelloPrefix = "Bonjour, "
portugueseHelloPrefix = "Olรก, "
)
```#### Golang testing
- file name must be `${something}_test.go`
- `import "testing"`
- the test function must start with `Test`
- test function takes only one argument `t *testing.T` (it's your "hook" into the testing framework)
- `t.Errorf` prints a message when a test fails.
- `%q` means "string surrounded with double quotes", in the string format context
- subtests go in `t.Run("test name", testFunction)`. Example:```go
func TestHello(t *testing.T) {
// ๐ t.Run(testName, testFunction)
t.Run("say hello to people", func(t *testing.T) {
actual := Hello("Chris")
expected := "Hello, Chris!"
assertCorrectMessage(t, actual, expected)
})// ๐ t.Run(testName, testFunction)
t.Run("say 'Hello, World!' when passing empty string", func(t *testing.T) {
actual := Hello("")
expected := "Hello, World!"
assertCorrectMessage(t, actual, expected)
})
}// comments about this helper function right after this codeblock
func assertCorrectMessage(t testing.TB, actual, expected string) {
t.Helper() // <-- pra que isso?
if actual != expected {
t.Errorf("expected: %q; actual: %q", expected, actual)
}
}
```- For helper functions, accept `testing.TB` is a good idea.
- `t.Helper` is needed to report the caller line number when the test fails
(not the line number in the helper function)## Integers
### Testable Examples
[Official article](https://go.dev/blog/examples).
Here's an example:
```go
func ExampleAdd() {
sum := Add(1, 5)
fmt.Println(sum)
// Output: 6
}
```The special comment `// Output: 6` makes the example to be executed.
This example also goes to the documentation of your package. You can check by
running `godoc -http :8000` and looking for the `Integers` package.## Iteration
### Golang
In Go you iterate using `for`. There are **no** `while`, `do`, `until` keywords.
It's usually used like other C-like languages:
```go
for i := 0; i < 5; i++ {
repeated += character
}
```Other ways of using `for` are listed here:
### Benchmarking
Example:
```go
func BenchmarkRepeat(b *testing.B) {
for i := 0; i < b.N; i++ {
Repeat("a")
}
}
```- `testing.B` gives you access to the (cryptic) `b.N`.
- the benchmark code is executed `b.N` times and measures how long it takes.
- the amount of times shouldn't matter, the framework determine what is a "good" value.
- run the benchmark with `go test -bench=.`
- the results show how many times the code was executed and how many nanoseconds it took to run.## Arrays
### Golang
Arrays can be initialized in two ways:
- `[N]type{value1, value2, ..., valueN}`
- example: `numbers := [5]int{1, 2, 3, 4, 5}`
- `[...]type{value1, value2, ..., valueN}`
- example: `numbers := [...]int{1, 2, 3, 4, 5}`The `%v` placeholder print the variable in the "default" format (in this case
an array).Let's check the `range` instruction:
```go
func Sum(numbers [5]int) int {
sum := 0
// numbers is the array given as argument
for _, number := range numbers {
sum += number
}
return sum
}
```- `range` let you iterate over an array
- on each iteration it returns two values: the index and the value
- in the example we are choosing to ignore the index by using the
`_` [blank identifier](https://go.dev/doc/effective_go#blank)## Slices
### Golang
The [slice type](https://go.dev/doc/effective_go#slices) allows us to have
collections of any size. The syntax is very similar to arrays, just omit
the size.Example: `mySlice := []int{1, 2, 3}`
Checking equality of slices:
```go
import "reflect"reflect.DeepEqual(slice1, slice2)
```Adding elements to a slice:
```go
// append() creates a new slice, therefore you need to assign the variable again
mySlice = append(mySlice, newElement)// you can use append() to merge two slices:
mySlice = append(mySlice, anotherSlice...)
```### Golang testing
Check the coverage with
```bash
go test -cover
```## Structs, Methods and Interfaces
### Golang
```go
// declaring a struct
type Rectangle struct {
Width float64
Height float64
}// declaring a method for a struct
func (r Rectangle) Area() float64 {
return r.Height * r.Width
}
```An interesting thing about interfaces in Go (which makes me remember Duck Typing):
**interface resolution is implicit**.Here's an example of an interface:
```go
type Shape interface {
Area() float64
}
```Once this ๐ is declared **any** struct witha method called `Area()` that returns
a `float64` is automatically considered a `Shape`.We don't need to explicitly say "My type Foo implements interface Bar".
### Golang testing
I learned about Table Driven Tests. It's useful but not that easy to read
(without some training).Here's an example:
```go
func TestArea(t *testing.T) {
// using Table Drive Tests
areaTests := []struct {
name string
shape Shape
hasArea float64
}{
{
name: "Rectangle",
shape: Rectangle{Width: 12, Height: 6},
hasArea: 72.0,
},
{
name: "Circle",
shape: Circle{Radius: 10},
hasArea: 314.1592653589793,
},
{
name: "Triangle",
shape: Triangle{Base: 12, Height: 6},
hasArea: 36.0,
},
}for _, tt := range areaTests {
// using tt.name to use it as the `t.Run` test name
t.Run(tt.name, func(t *testing.T) {
got := tt.shape.Area()
if got != tt.hasArea {
// the `%#v` format string prints the struct with values in its fields
t.Errorf("%#v got %g; want %g", tt.shape, got, tt.hasArea)
}
})
}
}
```