-
-
Notifications
You must be signed in to change notification settings - Fork 666
Concept stringers with exercise #2208
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
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
31ffc10
Concept stringers with exercise
norbs57 379c59e
Update exercises/concept/meteorology/.meta/design.md
norbs57 842f6c0
Merge branch 'exercism:main' into stringers
norbs57 7538af2
Update introduction.md
norbs57 bdb30da
Merge branch 'stringers' of https://github.com/norbs57/go into stringers
norbs57 b231af3
Changed DistanceUnit type to int in documentation
norbs57 7b4e89f
Update concepts/stringers/about.md
norbs57 d8945e7
Update exercises/concept/meteorology/.meta/design.md
norbs57 a2814b9
Update exercises/concept/meteorology/.meta/design.md
norbs57 be4a656
Update exercises/concept/meteorology/.meta/design.md
norbs57 343e960
Stringers: miscellaneous updates in response to comments received
norbs57 c678303
Merge branch 'stringers' of https://github.com/norbs57/go into stringers
norbs57 dd99a30
Finishing up the exercise
andrerfcsantos File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"blurb": "Stringer is an interface for defining the string format of values.", | ||
"authors": [ | ||
"norbs57" | ||
], | ||
"contributors": [ | ||
"andrerfcsantos" | ||
] | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# 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 | ||
} | ||
``` | ||
|
||
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 | ||
|
||
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 int | ||
|
||
const ( | ||
Kilometer DistanceUnit = 0 | ||
Mile DistanceUnit = 1 | ||
) | ||
|
||
type Distance struct { | ||
number float64 | ||
unit DistanceUnit | ||
} | ||
``` | ||
|
||
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 | ||
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` for `DistanceUnit` and `Distance` types by adding a `String` method to each type: | ||
|
||
```go | ||
func (sc DistanceUnit) String() string { | ||
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 | ||
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# 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 | ||
} | ||
``` | ||
|
||
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 | ||
|
||
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 int | ||
|
||
const ( | ||
Kilometer DistanceUnit = 0 | ||
Mile DistanceUnit = 1 | ||
) | ||
|
||
type Distance struct { | ||
number float64 | ||
unit DistanceUnit | ||
} | ||
``` | ||
|
||
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 | ||
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` for `DistanceUnit` and `Distance` types by adding a `String` method to each type: | ||
|
||
```go | ||
func (sc DistanceUnit) String() string { | ||
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 | ||
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Hints | ||
|
||
## 1. Implement the `Stringer` interface for type `TemperatureUnit` | ||
|
||
- 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` | ||
|
||
- 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` | ||
|
||
- 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` | ||
|
||
- 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] | ||
|
||
|
||
[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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# 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`. | ||
|
||
## 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 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 | ||
andrerfcsantos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
temperatureUnit := Celsius | ||
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 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 | ||
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, 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 | ||
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. | ||
|
||
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 | ||
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: | ||
|
||
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 | ||
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 | ||
``` |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.