mirror of
https://github.com/bootdotdev/fcc-learn-golang-assets.git
synced 2025-12-17 02:31:17 +00:00
first
This commit is contained in:
51
course/6-errors/exercises/1-errors/code.go
Normal file
51
course/6-errors/exercises/1-errors/code.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func sendSMSToCouple(msgToCustomer, msgToSpouse string) (float64, error) {
|
||||
// ?
|
||||
}
|
||||
|
||||
// don't edit below this line
|
||||
|
||||
func sendSMS(message string) (float64, error) {
|
||||
const maxTextLen = 25
|
||||
const costPerChar = .0002
|
||||
if len(message) > maxTextLen {
|
||||
return 0.0, fmt.Errorf("can't send texts over %v characters", maxTextLen)
|
||||
}
|
||||
return costPerChar * float64(len(message)), nil
|
||||
}
|
||||
|
||||
func test(msgToCustomer, msgToSpouse string) {
|
||||
defer fmt.Println("========")
|
||||
fmt.Println("Message for customer:", msgToCustomer)
|
||||
fmt.Println("Message for spouse:", msgToSpouse)
|
||||
totalCost, err := sendSMSToCouple(msgToCustomer, msgToSpouse)
|
||||
if err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Total cost: $%.4f\n", totalCost)
|
||||
}
|
||||
|
||||
func main() {
|
||||
test(
|
||||
"Thanks for coming in to our flower shop today!",
|
||||
"We hope you enjoyed your gift.",
|
||||
)
|
||||
test(
|
||||
"Thanks for joining us!",
|
||||
"Have a good day.",
|
||||
)
|
||||
test(
|
||||
"Thank you.",
|
||||
"Enjoy!",
|
||||
)
|
||||
test(
|
||||
"We loved having you in!",
|
||||
"We hope the rest of your evening is absolutely fantastic.",
|
||||
)
|
||||
}
|
||||
60
course/6-errors/exercises/1-errors/complete.go
Normal file
60
course/6-errors/exercises/1-errors/complete.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func sendSMSToCouple(msgToCustomer, msgToSpouse string) (float64, error) {
|
||||
cost, err := sendSMS(msgToCustomer)
|
||||
if err != nil {
|
||||
return 0.0, err
|
||||
}
|
||||
|
||||
costSpouse, err := sendSMS(msgToSpouse)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return costSpouse + cost, nil
|
||||
}
|
||||
|
||||
// don't edit below this line
|
||||
|
||||
func sendSMS(message string) (float64, error) {
|
||||
const maxTextLen = 25
|
||||
const costPerChar = .0002
|
||||
if len(message) > maxTextLen {
|
||||
return 0.0, fmt.Errorf("can't send texts over %v characters", maxTextLen)
|
||||
}
|
||||
return costPerChar * float64(len(message)), nil
|
||||
}
|
||||
|
||||
func test(msgToCustomer, msgToSpouse string) {
|
||||
defer fmt.Println("========")
|
||||
fmt.Println("Message for customer:", msgToCustomer)
|
||||
fmt.Println("Message for spouse:", msgToSpouse)
|
||||
totalCost, err := sendSMSToCouple(msgToCustomer, msgToSpouse)
|
||||
if err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Total cost: $%.4f\n", totalCost)
|
||||
}
|
||||
|
||||
func main() {
|
||||
test(
|
||||
"Thanks for coming in to our flower shop today!",
|
||||
"We hope you enjoyed your gift.",
|
||||
)
|
||||
test(
|
||||
"Thanks for joining us!",
|
||||
"Have a good day.",
|
||||
)
|
||||
test(
|
||||
"Thank you.",
|
||||
"Enjoy!",
|
||||
)
|
||||
test(
|
||||
"We loved having you in!",
|
||||
"We hope the rest of your evening is absolutely fantastic.",
|
||||
)
|
||||
}
|
||||
16
course/6-errors/exercises/1-errors/expected.txt
Normal file
16
course/6-errors/exercises/1-errors/expected.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
Message for customer: Thanks for coming in to our flower shop today!
|
||||
Message for spouse: We hope you enjoyed your gift.
|
||||
Error: can't send texts over 25 characters
|
||||
========
|
||||
Message for customer: Thanks for joining us!
|
||||
Message for spouse: Have a good day.
|
||||
Total cost: $0.0076
|
||||
========
|
||||
Message for customer: Thank you.
|
||||
Message for spouse: Enjoy!
|
||||
Total cost: $0.0032
|
||||
========
|
||||
Message for customer: We loved having you in!
|
||||
Message for spouse: We hope the rest of your evening is absolutely fantastic.
|
||||
Error: can't send texts over 25 characters
|
||||
========
|
||||
40
course/6-errors/exercises/1-errors/readme.md
Normal file
40
course/6-errors/exercises/1-errors/readme.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# The Error Interface
|
||||
|
||||
Go programs express errors with `error` values. An Error is any type that implements the simple built-in [error interface](https://blog.golang.org/error-handling-and-go):
|
||||
|
||||
```go
|
||||
type error interface {
|
||||
Error() string
|
||||
}
|
||||
```
|
||||
|
||||
When something can go wrong in a function, that function should return an `error` as its last return value. Any code that calls a function that can return an `error` should handle errors by testing whether the error is `nil`.
|
||||
|
||||
```go
|
||||
// Atoi converts a stringified number to an interger
|
||||
i, err := strconv.Atoi("42b")
|
||||
if err != nil {
|
||||
fmt.Println("couldn't convert:", err)
|
||||
// because "42b" isn't a valid integer, we print:
|
||||
// couldn't convert: strconv.Atoi: parsing "42b": invalid syntax
|
||||
// Note:
|
||||
// 'parsing "42b": invalid syntax' is returned by the .Error() method
|
||||
return
|
||||
}
|
||||
// if we get here, then
|
||||
// i was converted successfully
|
||||
```
|
||||
|
||||
A `nil` error denotes success; a non-nil error denotes failure.
|
||||
|
||||
## Assignment
|
||||
|
||||
We offer a product that allows businesses that use Textio to send pairs of messages to couples. It is mostly used by flower shops and movie theaters.
|
||||
|
||||
Complete the `sendSMSToCouple` function. It should send 2 messages, first to the customer, then to the customer's spouse.
|
||||
|
||||
1. Use `sendSMS()` to send the `msgToCustomer`. If an error is encountered, return `0.0` and the error.
|
||||
2. Do the same for the `msgToSpouse`
|
||||
3. If both messages are sent successfully, return the total cost of the messages added together.
|
||||
|
||||
*When you return a non-nil error in Go, it's conventional to return the "zero" values of all other return values.*
|
||||
20
course/6-errors/exercises/2-formatting_strings/code.go
Normal file
20
course/6-errors/exercises/2-formatting_strings/code.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
func getSMSErrorString(cost float64, recipient string) string {
|
||||
// ?
|
||||
}
|
||||
|
||||
// don't edit below this line
|
||||
|
||||
func test(cost float64, recipient string) {
|
||||
s := getSMSErrorString(cost, recipient)
|
||||
fmt.Println(s)
|
||||
fmt.Println("====================================")
|
||||
}
|
||||
|
||||
func main() {
|
||||
test(1.4, "+1 (435) 555 0923")
|
||||
test(2.1, "+2 (702) 555 3452")
|
||||
test(32.1, "+1 (801) 555 7456")
|
||||
test(14.4, "+1 (234) 555 6545")
|
||||
}
|
||||
27
course/6-errors/exercises/2-formatting_strings/complete.go
Normal file
27
course/6-errors/exercises/2-formatting_strings/complete.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func getSMSErrorString(cost float64, recipient string) string {
|
||||
return fmt.Sprintf("SMS that costs $%.2f to be sent to '%v' can not be sent",
|
||||
cost,
|
||||
recipient,
|
||||
)
|
||||
}
|
||||
|
||||
// don't edit below this line
|
||||
|
||||
func test(cost float64, recipient string) {
|
||||
s := getSMSErrorString(cost, recipient)
|
||||
fmt.Println(s)
|
||||
fmt.Println("====================================")
|
||||
}
|
||||
|
||||
func main() {
|
||||
test(1.4, "+1 (435) 555 0923")
|
||||
test(2.1, "+2 (702) 555 3452")
|
||||
test(32.1, "+1 (801) 555 7456")
|
||||
test(14.4, "+1 (234) 555 6545")
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
SMS that costs $1.40 to be sent to '+1 (435) 555 0923' can not be sent
|
||||
====================================
|
||||
SMS that costs $2.10 to be sent to '+2 (702) 555 3452' can not be sent
|
||||
====================================
|
||||
SMS that costs $32.10 to be sent to '+1 (801) 555 7456' can not be sent
|
||||
====================================
|
||||
SMS that costs $14.40 to be sent to '+1 (234) 555 6545' can not be sent
|
||||
====================================
|
||||
47
course/6-errors/exercises/2-formatting_strings/readme.md
Normal file
47
course/6-errors/exercises/2-formatting_strings/readme.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Formatting strings review
|
||||
|
||||
A convenient way to format strings in Go is by using the standard library's [fmt.Sprintf()](https://pkg.go.dev/fmt#example-Sprintf) function. It's a string interpolation function, similar to JavaScript's built-in template literals. The `%v` substring uses the type's default formatting, which is often what you want.
|
||||
|
||||
### Default values
|
||||
|
||||
```go
|
||||
const name = "Kim"
|
||||
const age = 22
|
||||
s := fmt.Sprintf("%v is %v years old.", name, age)
|
||||
// s = "Kim is 22 years old."
|
||||
```
|
||||
|
||||
The equivalent JavaScript code:
|
||||
|
||||
```js
|
||||
const name = 'Kim'
|
||||
const age = 22
|
||||
s = `${name} is ${age} years old.`
|
||||
// s = "Kim is 22 years old."
|
||||
```
|
||||
|
||||
### Rounding floats
|
||||
|
||||
```go
|
||||
fmt.Printf("I am %f years old", 10.523)
|
||||
// I am 10.523000 years old
|
||||
|
||||
// The ".2" rounds the number to 2 decimal places
|
||||
fmt.Printf("I am %.2f years old", 10.523)
|
||||
// I am 10.53 years old
|
||||
```
|
||||
|
||||
## Assignment
|
||||
|
||||
We need better error logs for our backend developers to help them debug their code.
|
||||
|
||||
Complete the `getSMSErrorString()` function. It should return a string with this format:
|
||||
|
||||
```
|
||||
SMS that costs $COST to be sent to 'RECIPIENT' can not be sent
|
||||
```
|
||||
|
||||
* `COST` is the cost of the SMS, always showing the price formatted to 2 decimal places.
|
||||
* `RECIPIENT` is the stringified representation of the recipient's phone number
|
||||
|
||||
*Be sure to include the $ symbol and the single quotes*
|
||||
41
course/6-errors/exercises/3-custom_errors/code.go
Normal file
41
course/6-errors/exercises/3-custom_errors/code.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type divideError struct {
|
||||
dividend float64
|
||||
}
|
||||
|
||||
// ?
|
||||
|
||||
// don't edit below this line
|
||||
|
||||
func divide(dividend, divisor float64) (float64, error) {
|
||||
if divisor == 0 {
|
||||
// We convert the `divideError` struct to an `error` type by returning it
|
||||
// as an error. As an error type, when it's printed its default value
|
||||
// will be the result of the Error() method
|
||||
return 0, divideError{dividend: dividend}
|
||||
}
|
||||
return dividend / divisor, nil
|
||||
}
|
||||
|
||||
func test(dividend, divisor float64) {
|
||||
defer fmt.Println("====================================")
|
||||
fmt.Printf("Dividing %.2f by %.2f ...\n", dividend, divisor)
|
||||
quotient, err := divide(dividend, divisor)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Quotient: %.2f\n", quotient)
|
||||
}
|
||||
|
||||
func main() {
|
||||
test(10, 0)
|
||||
test(10, 2)
|
||||
test(15, 30)
|
||||
test(6, 3)
|
||||
}
|
||||
43
course/6-errors/exercises/3-custom_errors/complete.go
Normal file
43
course/6-errors/exercises/3-custom_errors/complete.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type divideError struct {
|
||||
dividend float64
|
||||
}
|
||||
|
||||
func (de divideError) Error() string {
|
||||
return fmt.Sprintf("can not divide %v by zero", de.dividend)
|
||||
}
|
||||
|
||||
// don't edit below this line
|
||||
|
||||
func divide(dividend, divisor float64) (float64, error) {
|
||||
if divisor == 0 {
|
||||
// We convert the `divideError` struct to an `error` type by returning it
|
||||
// as an error. As an error type, when it's printed its default value
|
||||
// will be the result of the Error() method
|
||||
return 0, divideError{dividend: dividend}
|
||||
}
|
||||
return dividend / divisor, nil
|
||||
}
|
||||
|
||||
func test(dividend, divisor float64) {
|
||||
defer fmt.Println("====================================")
|
||||
fmt.Printf("Dividing %.2f by %.2f ...\n", dividend, divisor)
|
||||
quotient, err := divide(dividend, divisor)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Quotient: %.2f\n", quotient)
|
||||
}
|
||||
|
||||
func main() {
|
||||
test(10, 0)
|
||||
test(10, 2)
|
||||
test(15, 30)
|
||||
test(6, 3)
|
||||
}
|
||||
12
course/6-errors/exercises/3-custom_errors/expected.txt
Normal file
12
course/6-errors/exercises/3-custom_errors/expected.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Dividing 10.00 by 0.00 ...
|
||||
can not divide 10 by zero
|
||||
====================================
|
||||
Dividing 10.00 by 2.00 ...
|
||||
Quotient: 5.00
|
||||
====================================
|
||||
Dividing 15.00 by 30.00 ...
|
||||
Quotient: 0.50
|
||||
====================================
|
||||
Dividing 6.00 by 3.00 ...
|
||||
Quotient: 2.00
|
||||
====================================
|
||||
36
course/6-errors/exercises/3-custom_errors/readme.md
Normal file
36
course/6-errors/exercises/3-custom_errors/readme.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# The Error Interface
|
||||
|
||||
Because errors are just interfaces, you can build your own custom types that implement the `error` interface. Here's an example of a `userError` struct that implements the `error` interface:
|
||||
|
||||
```go
|
||||
type userError struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (e userError) Error() string {
|
||||
return fmt.Sprintf("%v has a problem with their account", e.name)
|
||||
}
|
||||
```
|
||||
|
||||
It can then be used as an error:
|
||||
|
||||
```go
|
||||
func sendSMS(msg, userName string) error {
|
||||
if !canSendToUser(userName) {
|
||||
return userError{name: userName}
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Assignment
|
||||
|
||||
Our users are frequently trying to run custom analytics queries on their message deliverability metrics, and end up writing a bad query that tries to divide a number by zero. It's become such a problem, that we think it would be best to make a specific type of error for division by zero.
|
||||
|
||||
Update the code so that the `divideError` type implements the `error` interface. Its `Error()` method should just return a string formatted in the following way:
|
||||
|
||||
```
|
||||
can not divide DIVIDEND by zero
|
||||
```
|
||||
|
||||
Where `DIVIDEND` is the actual dividend of the `divideError`. Use the `%v` [verb](https://pkg.go.dev/fmt#hdr-Printing) to format the dividend as a float.
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"question": "What is the underlying type of an error?",
|
||||
"answers": [
|
||||
"Interface",
|
||||
"Struct",
|
||||
"String"
|
||||
]
|
||||
}
|
||||
5
course/6-errors/exercises/4a-errors_quiz/readme.md
Normal file
5
course/6-errors/exercises/4a-errors_quiz/readme.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Errors Quiz
|
||||
|
||||
Go programs express errors with `error` values. Error-values are any type that implements the simple built-in [error interface](https://blog.golang.org/error-handling-and-go).
|
||||
|
||||
Keep in mind that the way Go handles errors is fairly unique. Most languages treat errors as something special and different. For example, Python raises exception types and JavaScript throws and catches errors. In Go, an `error` is just another value that we handle like any other value - however, we want! There aren't any special keywords for dealing with them.
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"question": "Can a type be an error and also fulfill another interface?",
|
||||
"answers": [
|
||||
"Yes",
|
||||
"No"
|
||||
]
|
||||
}
|
||||
5
course/6-errors/exercises/4b-errors_quiz/readme.md
Normal file
5
course/6-errors/exercises/4b-errors_quiz/readme.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Errors Quiz
|
||||
|
||||
Go programs express errors with `error` values. Error-values are any type that implements the simple built-in [error interface](https://blog.golang.org/error-handling-and-go).
|
||||
|
||||
Keep in mind that the way Go handles errors is fairly unique. Most languages treat errors as something special and different. For example, Python raises exception types and JavaScript throws and catches errors. In Go, an `error` is just another value that we handle like any other value - however, we want! There aren't any special keywords for dealing with them.
|
||||
33
course/6-errors/exercises/5-errors_package/code.go
Normal file
33
course/6-errors/exercises/5-errors_package/code.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func divide(x, y float64) (float64, error) {
|
||||
if y == 0 {
|
||||
// ?
|
||||
}
|
||||
return x / y, nil
|
||||
}
|
||||
|
||||
// don't edit below this line
|
||||
|
||||
func test(x, y float64) {
|
||||
defer fmt.Println("====================================")
|
||||
fmt.Printf("Dividing %.2f by %.2f ...\n", x, y)
|
||||
quotient, err := divide(x, y)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Quotient: %.2f\n", quotient)
|
||||
}
|
||||
|
||||
func main() {
|
||||
test(10, 0)
|
||||
test(10, 2)
|
||||
test(15, 30)
|
||||
test(6, 3)
|
||||
}
|
||||
33
course/6-errors/exercises/5-errors_package/complete.go
Normal file
33
course/6-errors/exercises/5-errors_package/complete.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func divide(x, y float64) (float64, error) {
|
||||
if y == 0 {
|
||||
return 0, errors.New("no dividing by 0")
|
||||
}
|
||||
return x / y, nil
|
||||
}
|
||||
|
||||
// don't edit below this line
|
||||
|
||||
func test(x, y float64) {
|
||||
defer fmt.Println("====================================")
|
||||
fmt.Printf("Dividing %.2f by %.2f ...\n", x, y)
|
||||
quotient, err := divide(x, y)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Quotient: %.2f\n", quotient)
|
||||
}
|
||||
|
||||
func main() {
|
||||
test(10, 0)
|
||||
test(10, 2)
|
||||
test(15, 30)
|
||||
test(6, 3)
|
||||
}
|
||||
12
course/6-errors/exercises/5-errors_package/expected.txt
Normal file
12
course/6-errors/exercises/5-errors_package/expected.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Dividing 10.00 by 0.00 ...
|
||||
no dividing by 0
|
||||
====================================
|
||||
Dividing 10.00 by 2.00 ...
|
||||
Quotient: 5.00
|
||||
====================================
|
||||
Dividing 15.00 by 30.00 ...
|
||||
Quotient: 0.50
|
||||
====================================
|
||||
Dividing 6.00 by 3.00 ...
|
||||
Quotient: 2.00
|
||||
====================================
|
||||
15
course/6-errors/exercises/5-errors_package/readme.md
Normal file
15
course/6-errors/exercises/5-errors_package/readme.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# The Errors Package
|
||||
|
||||
The Go standard library provides an "errors" package that makes it easy to deal with errors.
|
||||
|
||||
Read the godoc for the [errors.New()](https://pkg.go.dev/errors#New) function, but here's a simple example:
|
||||
|
||||
```go
|
||||
var err error = errors.New("something went wrong")
|
||||
```
|
||||
|
||||
## Assignment
|
||||
|
||||
Twilio's software architects may have overcomplicated the requirements from the last coding assignment... oops. All we needed was a new generic error message that returns the string `no dividing by 0` when a user attempts to get us to perform the taboo.
|
||||
|
||||
Complete the `divide` function. Use the `errors.New()` function to return an error when `y == 0` that reads "no dividing by 0".
|
||||
Reference in New Issue
Block a user