Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concept stringers with exercise #2208

Merged
merged 13 commits into from
May 29, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions concepts/stringers/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"blurb": "Stringer is an interface for defining the string format of values.",
"authors": [
"norbs57"
],
"contributors": []
}
68 changes: 68 additions & 0 deletions concepts/stringers/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# About

[Stringer][stringer-interface] is an interface for defining the string format of values.

The interface consists of a single `String` method:

```go
type Stringer interface {
String() string
}
```

The [fmt][fmt-package] package (and many others) will look for this interface to print values.
norbs57 marked this conversation as resolved.
Show resolved Hide resolved

## Example: Distances

Assume we are working on an application that deals with geographical distances measured in different units.
We have defined types `DistanceUnit` and `Distance` as follows:

```go
type DistanceUnit string

const (
Kilometer DistanceUnit = 0
Mile DistanceUnit = 1
NauticalMile DistanceUnit = 2
norbs57 marked this conversation as resolved.
Show resolved Hide resolved
)

type Distance struct {
number float64
unit DistanceUnit
}
```

These types do not implement interface `Stringer` as they lack the `String` method.
Hence `fmt` functions will print `Distance` values using Go's "default format":

```go
var distances = []Distance{
{790.7, Kilometer},
{415.2, Mile},
{10_500, NauticalMile},
norbs57 marked this conversation as resolved.
Show resolved Hide resolved
}
fmt.Println(distances)
\\ => [{790.7 0} {415.2 1} {10500 2}]
norbs57 marked this conversation as resolved.
Show resolved Hide resolved
```

In order to make the output more informative, we implement interface `Stringer` by adding a `String` method to each type:

```go
func (sc DistanceUnit) String() string {
return [...]string{"km", "mi", "nmi"}[sc]
norbs57 marked this conversation as resolved.
Show resolved Hide resolved
}

func (d Distance) String() string {
return fmt.Sprintf("%v %v", d.number, d.unit)
}
```

`fmt` package functions will call these methods when formatting `Distance` values:

```go
fmt.Println(distances)
\\ => [790.7 km 415.2 mi 10500 nmi]
norbs57 marked this conversation as resolved.
Show resolved Hide resolved
```

[stringer-interface]: https://pkg.go.dev/fmt#Stringer
[fmt-package]: https://pkg.go.dev/fmt
68 changes: 68 additions & 0 deletions concepts/stringers/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Introduction

[Stringer][stringer-interface] is an interface for defining the string format of values.

The interface consists of a single `String` method:

```go
type Stringer interface {
String() string
}
```

The [fmt][fmt-package] package (and many others) will look for this interface to print values.

## Example: Distances

Assume we are working on an application that deals with geographical distances measured in different units.
We have defined types `DistanceUnit` and `Distance` as follows:

```go
type DistanceUnit string

const (
Kilometer DistanceUnit = 0
Mile DistanceUnit = 1
NauticalMile DistanceUnit = 2
)

type Distance struct {
number float64
unit DistanceUnit
}
```

These types do not implement interface `Stringer` as they lack the `String` method.
Hence `fmt` functions will print `Distance` values using Go's "default format":

```go
var distances = []Distance{
{790.7, Kilometer},
{415.2, Mile},
{10_500, NauticalMile},
}
fmt.Println(distances)
\\ => [{790.7 0} {415.2 1} {10500 2}]
```

In order to make the output more informative, we implement interface `Stringer` by adding a `String` method to each type:

```go
func (sc DistanceUnit) String() string {
return [...]string{"km", "mi", "nmi"}[sc]
}

func (d Distance) String() string {
return fmt.Sprintf("%v %v", d.number, d.unit)
}
```

`fmt` package functions will call these methods when formatting `Distance` values:

```go
fmt.Println(distances)
\\ => [790.7 km 415.2 mi 10500 nmi]
```

[stringer-interface]: https://pkg.go.dev/fmt#Stringer
[fmt-package]: https://pkg.go.dev/fmt
14 changes: 14 additions & 0 deletions concepts/stringers/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"url": "https://pkg.go.dev/fmt",
"description": "Go standard library: package fmt"
},
{
"url": "https://pkg.go.dev/fmt#Stringer",
"description": "Go standard library: interface Stringer"
},
{
"url": "https://go.dev/tour/methods/17",
"description": "A Tour of Go: Stringers"
}
]
21 changes: 21 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,22 @@
"slices"
],
"status": "beta"
},
{
"slug": "meteorology",
"name": "Meteorology",
"uuid": "09fc7443-f5a2-4b19-8331-f3d5df3e5165",
"concepts": [
"stringers"
],
"prerequisites": [
"strings",
"string-formatting",
"interfaces",
"methods",
"structs"
],
"status": "beta"
}
],
"practice": [
Expand Down Expand Up @@ -2067,6 +2083,11 @@
"slug": "strings-package",
"uuid": "33708451-a03f-44ce-be05-eaacc1d5793c"
},
{
"name": "Stringers",
"slug": "stringers",
"uuid": "288c0d5b-173a-4446-b9a6-05f91fddd63e"
},
{
"name": "Structs",
"slug": "structs",
Expand Down
9 changes: 9 additions & 0 deletions exercises/concept/meteorology/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Hints

## General

See [yourbasic.org][yourbasic-enum] for an example how to define a "enum" type with a `String` method.

[yourbasic-enum]: https://yourbasic.org/golang/iota/#complete-enum-type-with-strings-best-practice


35 changes: 35 additions & 0 deletions exercises/concept/meteorology/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Instructions

Your team is working on a meteorology application.
They have defined an API with various types and constants representing meteorological data, see file `meteorology.go`.

Your task is to add suitable `String` methods to all types so that they implement interface `Stringer`.
andrerfcsantos marked this conversation as resolved.
Show resolved Hide resolved

Values should be formatted as in the examples below:

```go
andrerfcsantos marked this conversation as resolved.
Show resolved Hide resolved
temperatureUnit := Celsius
fmt.Println(temperatureUnit)
andrerfcsantos marked this conversation as resolved.
Show resolved Hide resolved
// => C

temperature := Temperature{21, Celsius}
fmt.Println(temperature)
// => 21 °C

speedUnit := MilesPerHour
fmt.Println(speedUnit)
// => mph

windSpeed := Speed{18, KmPerHour}
fmt.Println(windSpeed)
// => 18 km/h

metData := MetData{"San Francisco", Temperature{57, Fahrenheit}, "NW", Speed{19, MilesPerHour}, 60},
fmt.Println(metData)
// => San Francisco: 57 °F, Wind NW at 19 mph, 60% Humidity
```

In the test data, you can assume that

- the unit of temperature will be either `Celsius` or `Fahrenheit`
- the unit of wind speed will be either `KmPerHour` or `MilesPerHour`
norbs57 marked this conversation as resolved.
Show resolved Hide resolved
68 changes: 68 additions & 0 deletions exercises/concept/meteorology/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Introduction

[Stringer][stringer-interface] is an interface for defining the string format of values.

The interface consists of a single `String` method:

```go
type Stringer interface {
String() string
}
```

The [fmt][fmt-package] package (and many others) will look for this interface to print values.

## Example: Distances

Assume we are working on an application that deals with geographical distances measured in different units.
We have defined types `DistanceUnit` and `Distance` as follows:

```go
type DistanceUnit string

const (
Kilometer DistanceUnit = 0
Mile DistanceUnit = 1
NauticalMile DistanceUnit = 2
)

type Distance struct {
number float64
unit DistanceUnit
}
```

These types do not implement interface `Stringer` as they lack the `String` method.
Hence `fmt` functions will print `Distance` values using Go's "default format":

```go
var distances = []Distance{
{790.7, Kilometer},
{415.2, Mile},
{10_500, NauticalMile},
}
fmt.Println(distances)
\\ => [{790.7 0} {415.2 1} {10500 2}]
```

In order to make the output more informative, we implement interface `Stringer` by adding a `String` method to each type:

```go
func (sc DistanceUnit) String() string {
return [...]string{"km", "mi", "nmi"}[sc]
}

func (d Distance) String() string {
return fmt.Sprintf("%v %v", d.number, d.unit)
}
```

`fmt` package functions will call these methods when formatting `Distance` values:

```go
fmt.Println(distances)
\\ => [790.7 km 415.2 mi 10500 nmi]
```

[stringer-interface]: https://pkg.go.dev/fmt#Stringer
[fmt-package]: https://pkg.go.dev/fmt
18 changes: 18 additions & 0 deletions exercises/concept/meteorology/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"blurb": "Learn how to work with interface Stringer",
"authors": [
"norbs57"
],
"contributors": [],
"files": {
"solution": [
"meteorology.go"
],
"test": [
"meteorology_test.go"
],
"exemplar": [
".meta/exemplar.go"
]
}
}
45 changes: 45 additions & 0 deletions exercises/concept/meteorology/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Design

## Goal

The goal here is to create a new concept exercise that teaches about structs that implement the `fmt.Stringer` interface.
That includes writing a concept and creating a new exercise.

## Learning objectives

The student should learn about the following topics and then practice them in the concept exercise:

- present the `fmt.Stringer` interface
- implement a struct that satisfies the `fmt.Stringer`
- the use of a type that satisfies `fmt.Stringer` with `fmt.Sprintf` and other methods of `fmt`
norbs57 marked this conversation as resolved.
Show resolved Hide resolved

## Concepts

- `stringers`

## Prerequisites

- `strings`
- `string-formatting`
- `interfaces`
- `methods`
- `structs`

These prerequisites should be listed in the `config.json` entry for the exercise.
The prerequisites above are a baseline of the prerequisites that might be needed for the exercise.
When implementing the exercise, feel free to add more prerequisites if the exercise needs them.

norbs57 marked this conversation as resolved.
Show resolved Hide resolved
## Story

Try to think of a story for the exercise that ties all the tasks together.
The story doesn't need to be highly complex.
Even a small story goes a long way to improve the enjoyment of the exercise.

norbs57 marked this conversation as resolved.
Show resolved Hide resolved
## Resources

Some links that might be helpful as a starting point and/or for the links section of the concept:

norbs57 marked this conversation as resolved.
Show resolved Hide resolved
- Tour of Go: [Stringers][tour-of-go-stringers]


[tour-of-go-stringers]: https://go.dev/tour/methods/17
Loading