Skip to content

Commit

Permalink
Finishing up the exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
andrerfcsantos committed May 29, 2022
1 parent c678303 commit dd99a30
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 126 deletions.
4 changes: 3 additions & 1 deletion concepts/stringers/.meta/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
"authors": [
"norbs57"
],
"contributors": []
"contributors": [
"andrerfcsantos"
]
}
47 changes: 31 additions & 16 deletions concepts/stringers/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type Stringer interface {
}
```

Types that want to implement this interface must have a `String()` method that returns a human-friendly string representation of the type. The [fmt][fmt-package] package (and many others) will look for this method to print values.
Types that want to implement this interface must have a `String()` method that returns a human-friendly string representation of the type. The [fmt][fmt-package] package (and many others) will look for this method to format and print values.

## Example: Distances

Expand All @@ -23,7 +23,6 @@ type DistanceUnit int
const (
Kilometer DistanceUnit = 0
Mile DistanceUnit = 1
NauticalMile DistanceUnit = 2
)

type Distance struct {
Expand All @@ -32,38 +31,54 @@ type Distance struct {
}
```

In the example above, `Kilometer` and `Mile` ane constants of type `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{
{number: 790.7, unit: Kilometer},
{number: 415.2, unit: Mile},
{number: 10_500, unit: NauticalMile},
}
fmt.Println(distances)
// Output: [{790.7 0} {415.2 1} {10500 2}]
```go
mileUnit := Mile
fmt.Sprint(mileUnit)
// => 1
// The result is '1' because that is the underlying value of the 'Mile' contant (see contant declarations above)

dist := Distance{number: 790.7, unit: Kilometer}
fmt.Sprint(dist)
// => {790.7 0}
// not a very useful output!
```

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

```go
func (sc DistanceUnit) String() string {
units := []string{"km", "mi", "nmi"}
units := []string{"km", "mi"}
return units[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)
// Output: [790.7 km 415.2 mi 10500 nmi]
kmUnit := Kilometer
kmUnit.String()
// => km

mileUnit := Mile
mileUnit.String()
// => mi

dist := Distance{
number: 790.7,
unit: Kilometer,
}
dist.String()
// => 790.7 km
```

[stringer-interface]: https://pkg.go.dev/fmt#Stringer
[fmt-package]: https://pkg.go.dev/fmt
[fmt-package]: https://pkg.go.dev/fmt
45 changes: 30 additions & 15 deletions concepts/stringers/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type Stringer interface {
}
```

Types that want to implement this interface must have a `String()` method that returns a human-friendly string representation of the type. The [fmt][fmt-package] package (and many others) will look for this method to print values.
Types that want to implement this interface must have a `String()` method that returns a human-friendly string representation of the type. The [fmt][fmt-package] package (and many others) will look for this method to format and print values.

## Example: Distances

Expand All @@ -23,7 +23,6 @@ type DistanceUnit int
const (
Kilometer DistanceUnit = 0
Mile DistanceUnit = 1
NauticalMile DistanceUnit = 2
)

type Distance struct {
Expand All @@ -32,37 +31,53 @@ type Distance struct {
}
```

In the example above, `Kilometer` and `Mile` ane constants of type `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{
{number: 790.7, unit: Kilometer},
{number: 415.2, unit: Mile},
{number: 10_500, unit: NauticalMile},
}
fmt.Println(distances)
// Output: [{790.7 0} {415.2 1} {10500 2}]
```go
mileUnit := Mile
fmt.Sprint(mileUnit)
// => 1
// The result is '1' because that is the underlying value of the 'Mile' contant (see contant declarations above)

dist := Distance{number: 790.7, unit: Kilometer}
fmt.Sprint(dist)
// => {790.7 0}
// not a very useful output!
```

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

```go
func (sc DistanceUnit) String() string {
units := []string{"km", "mi", "nmi"}
units := []string{"km", "mi"}
return units[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)
// Output: [790.7 km 415.2 mi 10500 nmi]
kmUnit := Kilometer
kmUnit.String()
// => km

mileUnit := Mile
mileUnit.String()
// => mi

dist := Distance{
number: 790.7,
unit: Kilometer,
}
dist.String()
// => 790.7 km
```

[stringer-interface]: https://pkg.go.dev/fmt#Stringer
Expand Down
33 changes: 25 additions & 8 deletions exercises/concept/meteorology/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
# Hints

## 1. Implement the `Stringer` interface for type `TemperatureUnit`

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

- The type `TemperatureUnit` is already created for you and represents a temperature unit
- Note that there are already 2 constants created for you that are of this type: `Celsius` and `Fahrenheit`, representing a temperature in Celsius and Fahrenheit, respectively
- Add a `String()` method to the `TemperatureUnit` type so it satisfies the `Stringer` interface. This method must return the string `"°C"` if the temperature unit is Celsius or `"°F"` if the temperature unit is Fahrenheit

## 2. Implement the `Stringer` interface for type `Temperature`

See [yourbasic.org][yourbasic-enum] for an example how to define a "enum" type with a `String` method.
- Add a `String()` method to the `Temperature` type so it satisfies the `Stringer` interface
- The `String()` method should return a string with the numeric value for the temperature and the temperature unit separated by a space (`<temperature> <unit>`)
- The `Temperature` struct contains a `TemperatureUnit` and a `int`. You can use [fmt.Sprintf][sprintf] to help you format this string
- Since `TemperatureUnit` already implements the `Stringer` interface (from task 1), the functions of the `fmt` package like [fmt.Sprintf][sprintf] will know how to format it when you use the `%v` or `%s` [formatting verbs][fmt]

## 3. Implement the `Stringer` interface for type `SpeedUnit`

See [yourbasic.org][yourbasic-enum] for an example how to define a "enum" type with a `String` method.
- The type `SpeedUnit` is already created for you and represents a temperature unit
- Note that there are already 2 constants created for you that are of this type: `KmPerHour` and `MilesPerHour`, representing a speed in kilometers per hour and miles per hour, respectively
- Add a `String()` method to the `SpeedUnit` type so it satisfies the `Stringer` interface. This method must return the string `"km/h"` if the speed unit is kilometers per hour or `"mph"` if the speed unit is miles per hour.

## 4. Implement the `Stringer` interface for `Speed`

See [yourbasic.org][yourbasic-enum] for an example how to define a "enum" type with a `String` method.
- Add a `String()` method to the `Speed` type so it satisfies the `Stringer` interface
- The `String()` method should return a string with the numeric value for the speed and the speed unit separated by a space (`<speed> <unit>`)
- The `Speed` contains a `SpeedUnit` and a `int`. You can use [fmt.Sprintf][sprintf] to help you format this string
- Since `TemperatureUnit` struct already implements the `Stringer` interface (from task 3), the functions of the `fmt` package like [fmt.Sprintf][sprintf] will know how to format it when you use the `%v` or `%s` [formatting verbs][fmt]
- To insert a `%` in the final string when using [fmt.Sprintf][sprintf], use `%%` in the formatting string.

## 5. Implement the `Stringer` interface for type `MeteorologyData`

- The `Speed` contains a `Temperature` and a `Speed` fields, among other fields. You can use [fmt.Sprintf][sprintf] to help you format this string
- The `String` method should return the meteorology data in the following format: `"<location>: <temperature>, Wind <wind_speed> at <wind_direction>, <humidity>% Humidity"`
- Since the `Temperature` and `Speed` types already implement the `Stringer` interface (from task 2 and 4), the functions of the `fmt` package like [fmt.Sprintf][sprintf] will know how to format it when you use the `%v` or `%s` [formatting verbs][fmt]

## 5. Implement the `Stringer` interface for type `MetData`

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

[fmt]: https://pkg.go.dev/fmt
[sprint]: https://pkg.go.dev/fmt#Sprint
[sprintf]: https://pkg.go.dev/fmt#Sprintf
[yourbasic-enum]: https://yourbasic.org/golang/iota/#complete-enum-type-with-strings-best-practice
108 changes: 89 additions & 19 deletions exercises/concept/meteorology/.docs/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,121 @@ Your task is to add suitable `String` methods to all types so that they implemen

## 1. Implement the `Stringer` interface for type `TemperatureUnit`

After some discussion, the team have agreed that the unit of temperature will be either `Celsius` or `Fahrenheit`. Values should be formatted as shown below:
After some discussion, the team have agreed that the unit of temperature will be either `Celsius` or `Fahrenheit`. Values should be formatted as shown in the examples below.

Make the `TemperatureUnit` type implement the `Stringer` interface by adding a `String` method to it. This method must return the string `"°C"` if the temperature unit is Celsius or `"°F"` if the temperature unit is Fahrenheit.

```go
temperatureUnit := Celsius
fmt.Println(temperatureUnit)
// Output: C
celsiusUnit := Celsius
fahrenheitUnit := Fahrenheit

celsiusUnit.String()
// => °C
fahrenheitUnit.String()
// => °F
fmt.Sprint(celsiusUnit)
// => °C
```

## 2. Implement the `Stringer` interface for type `Temperature`

Temperature values consist of an integer and a temperature unit. They should be formatted as in the example below:
Temperature values consist of an integer and a temperature unit. They should be formatted as in the examples below.

For that to happen, make the `Temperature` type implement the `Stringer` interface by adding a `String` method to it. This method should return a string with the numeric value for the temperature and the temperature unit separated by a space: `<temperature> <unit>`:


```go
temperature := Temperature{21, Celsius}
fmt.Println(temperature)
// Output: 21 °C
celsiusTemp := Temperature{
degree: 21,
unit: Celsius,
}
celsiusTemp.String()
// => 21 °C
fmt.Sprint(celsiusTemp)
// => 21 °C

fahrenheitTemp := Temperature{
degree: 75,
unit: Fahrenheit,
}
fahrenheitTemp.String()
// => 75 °F
fmt.Sprint(fahrenheitTemp)
// => 75 °F
```

## 3. Implement the `Stringer` interface for type `SpeedUnit`

After lengthy discussions, thee team has agreed that the unit of wind speed will be either `KmPerHour` or `MilesPerHour`. Values should be formatted as shown below:
After lengthy discussions, the team has agreed that the unit of wind speed will be either `KmPerHour` or `MilesPerHour`. Values should be formatted as the examples below.

For that to happen, make the `SpeedUnit` type implement the `Stringer` interface by adding a `String` method to it. This method must return the string `"km/h"` if the speed unit is kilometers per hour or `"mph"` if the speed unit is miles per hour:


```go
speedUnit := MilesPerHour
fmt.Println(speedUnit)
// Output: mph
mphUnit := MilesPerHour
mphUnit.String()
// => mph
fmt.Sprint(mphUnit)
// => mph

kmhUnit := KmPerHour
kmhUnit.String()
// => km/h
fmt.Sprint(mphUnit)
// => km/h
```

## 4. Implement the `Stringer` interface for `Speed`

Wind speed values consist of an integer and a speed unit. They should be formatted as in the example below:
Wind speed values consist of an integer and a speed unit. They should be formatted as in the example below.

For that to happen, make the `Speed` type implement the `Stringer` interface by adding a `String` method to it. This method should return a string with the numeric value for the speed and the speed unit separated by a space: `<speed> <unit>`:

```go
windSpeed := Speed{18, KmPerHour}
fmt.Println(windSpeed)
// Output: 18 km/h
windSpeedNow := Speed{
magnitude: 18,
unit: KmPerHour,
}
windSpeedNow.String(windSpeedNow)
// => 18 km/h
fmt.Sprintf(windSpeedNow)
// => 18 km/h

windSpeedYesterday := Speed{
magnitude: 22,
unit: MilesPerHour,
}
windSpeedYesterday.String(windSpeedYesterday)
// => 22 mph
fmt.Sprint(windSpeedYesterday)
// => 22 mph
```

## 5. Implement the `Stringer` interface for type `MetData`

Meteorological data specifies location, temperature, wind direction, wind speed
and humidity. It should be formatted as in the example below:
and humidity. It should be formatted as in the example below:

For that to happen, make the `MeteorologyData` type implement the `Stringer` interface by adding a `String` method to it. This method should return the meteorology data in the following format: `"<location>: <temperature>, Wind <wind_speed> at <wind_direction>, <humidity>% Humidity"`:

```go
metData := MetData{"San Francisco", Temperature{57, Fahrenheit}, "NW", Speed{19, MilesPerHour}, 60}
fmt.Println(metData)
// Output: San Francisco: 57 °F, Wind NW at 19 mph, 60% Humidity
sfData := MeteorologyData{
location: "San Francisco",
temperature: Temperature{
degree: 57,
unit: Fahrenheit
},
windDirection: "NW",
windSpeed: Speed{
magnitude: 19,
unit: MilesPerHour
},
humidity: 60
}

sfData.String()
// => San Francisco: 57 °F, Wind NW at 19 mph, 60% Humidity
fmt.Sprint(sfData)
// => San Francisco: 57 °F, Wind NW at 19 mph, 60% Humidity
```
Loading

0 comments on commit dd99a30

Please sign in to comment.