Skip to content

Commit

Permalink
Concept stringers with exercise
Browse files Browse the repository at this point in the history
Fixes #2184
New concept stringers
New concept exercise Meteorology
  • Loading branch information
norbs57 committed Apr 29, 2022
1 parent 7659cc3 commit 7608dc9
Show file tree
Hide file tree
Showing 14 changed files with 599 additions and 0 deletions.
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.

## 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
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 all types so that they implement interface `Stringer`.

Values should be formatted as in the examples below:

```go
temperatureUnit := Celsius
fmt.Println(temperatureUnit)
// => 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 be either `Celsius` or `Fahrenheit`
- the unit of wind speed will be either `KmPerHour` or `MilesPerHour`
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`

## 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.

## 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.

## Resources

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

- Tour of Go: [Stringers][tour-of-go-stringers]


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

0 comments on commit 7608dc9

Please sign in to comment.