Skip to content

Commit 6fde5f1

Browse files
committed
[ADD] panic, defer, recover
1 parent 753f8f2 commit 6fde5f1

9 files changed

+365
-1
lines changed

codes/defer.go

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
)
7+
8+
func main() {
9+
10+
f := createFile("/tmp/defer.txt")
11+
defer closeFile(f)
12+
writeFile(f)
13+
}
14+
15+
func createFile(p string) *os.File {
16+
fmt.Println("creating")
17+
f, err := os.Create(p)
18+
if err != nil {
19+
panic(err)
20+
}
21+
return f
22+
}
23+
24+
func writeFile(f *os.File) {
25+
fmt.Println("writing")
26+
fmt.Fprintln(f, "data")
27+
28+
}
29+
30+
func closeFile(f *os.File) {
31+
fmt.Println("closing")
32+
err := f.Close()
33+
34+
if err != nil {
35+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
36+
os.Exit(1)
37+
}
38+
}

codes/panic.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main
2+
3+
import "os"
4+
5+
func main() {
6+
7+
panic("a problem")
8+
9+
_, err := os.Create("/tmp/file")
10+
if err != nil {
11+
panic(err)
12+
}
13+
}

codes/recover.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func mayPanic() {
6+
panic("a problem")
7+
}
8+
9+
func main() {
10+
11+
defer func() {
12+
if r := recover(); r != nil {
13+
14+
fmt.Println("Recovered. Error:\n", r)
15+
}
16+
}()
17+
18+
mayPanic()
19+
20+
fmt.Println("After mayPanic()")
21+
}

codes/sorting-by-functions.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"cmp"
5+
"fmt"
6+
"slices"
7+
)
8+
9+
func main() {
10+
fruits := []string{"peach", "banana", "kiwi"}
11+
12+
lenCmp := func(a, b string) int {
13+
return cmp.Compare(len(a), len(b))
14+
}
15+
16+
slices.SortFunc(fruits, lenCmp)
17+
fmt.Println(fruits)
18+
19+
type Person struct {
20+
name string
21+
age int
22+
}
23+
24+
people := []Person{
25+
Person{name: "Jax", age: 37},
26+
Person{name: "TJ", age: 25},
27+
Person{name: "Alex", age: 72},
28+
}
29+
30+
slices.SortFunc(people,
31+
func(a, b Person) int {
32+
return cmp.Compare(a.age, b.age)
33+
})
34+
fmt.Println(people)
35+
}
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
This Go code showcases the use of a custom sorting package named "slices" along with a comparison package "cmp" to perform sorting on slices. It demonstrates the flexibility of custom sorting by providing a comparison function.
2+
3+
Let's go through the code with inline comments and explanations:
4+
5+
```go
6+
// Importing necessary packages.
7+
package main
8+
9+
import (
10+
"cmp" // Custom comparison package
11+
"fmt"
12+
"slices" // Custom slices package for sorting
13+
)
14+
15+
// The main function, where the execution of the program begins.
16+
func main() {
17+
// Example with a slice of strings
18+
fruits := []string{"peach", "banana", "kiwi"}
19+
20+
// Defining a custom comparison function for sorting based on string length
21+
lenCmp := func(a, b string) int {
22+
return cmp.Compare(len(a), len(b))
23+
}
24+
25+
// Using the SortFunc function from the slices package to sort the string slice using the custom comparison function.
26+
slices.SortFunc(fruits, lenCmp)
27+
28+
// Printing the sorted string slice.
29+
fmt.Println(fruits)
30+
31+
// Example with a slice of custom type (Person)
32+
type Person struct {
33+
name string
34+
age int
35+
}
36+
37+
// Creating a slice of Person instances
38+
people := []Person{
39+
{name: "Jax", age: 37},
40+
{name: "TJ", age: 25},
41+
{name: "Alex", age: 72},
42+
}
43+
44+
// Using the SortFunc function from the slices package to sort the Person slice using a custom comparison function.
45+
slices.SortFunc(people,
46+
func(a, b Person) int {
47+
return cmp.Compare(a.age, b.age)
48+
})
49+
50+
// Printing the sorted Person slice.
51+
fmt.Println(people)
52+
}
53+
```
54+
### Output
55+
```
56+
[kiwi peach banana]
57+
[{TJ 25} {Jax 37} {Alex 72}]
58+
```
59+
Now, let's discuss the `slices` package and the use of `SortFunc`:
60+
61+
#### `slices.SortFunc(slice interface{}, less func(i, j int) int)`
62+
- This function takes a slice of any type (interface{}) and a custom comparison function `less`.
63+
- The comparison function is used to determine the order of elements in the slice.
64+
- The sorting is performed in-place, modifying the original slice.
65+
66+
The `main` function demonstrates the use of `SortFunc` with both a string slice (`fruits`) and a slice of custom type (`people`). It shows how to provide a custom comparison function (`lenCmp` for strings and an anonymous function for `Person` instances) to achieve sorting based on specific criteria.
67+
68+
Make sure that the `slices` and `cmp` packages are implemented correctly and are available in the same directory or in the Go module path for this program to work. The `import "slices"` and `import "cmp"` statements assume that there are files named `slices.go` and `cmp.go` containing the respective packages in the same directory as your main program.

documentation/45-panic.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
This Go code demonstrates the use of the `panic` function, which is used to terminate the normal execution flow of a program and initiate a panic. Let's go through the code with inline comments and explanations:
2+
3+
```go
4+
// Importing necessary package.
5+
import "os"
6+
7+
// The main function, where the execution of the program begins.
8+
func main() {
9+
// Initiating a panic with a custom error message.
10+
panic("a problem")
11+
12+
// The code below this line will not be executed due to the preceding panic.
13+
14+
// Attempting to create a file (this code will not be reached).
15+
_, err := os.Create("/tmp/file")
16+
17+
// Checking if an error occurred during file creation (this code will not be reached).
18+
if err != nil {
19+
// Initiating a panic with the error message if an error is present.
20+
panic(err)
21+
}
22+
}
23+
```
24+
### Output
25+
```
26+
panic: a problem
27+
28+
goroutine 1 [running]:
29+
main.main()
30+
..:/...../..../..../panic.go:7 +0x25
31+
exit status 2
32+
```
33+
Explanation:
34+
35+
1. **`panic("a problem")`:**
36+
- This line explicitly triggers a panic with the message "a problem."
37+
- When a panic occurs, the normal flow of the program is halted, and the program terminates abruptly.
38+
39+
2. **`_, err := os.Create("/tmp/file")`:**
40+
- This line attempts to create a file in the "/tmp" directory.
41+
- Note that this line and the subsequent lines will not be executed if a panic occurs earlier in the code.
42+
43+
3. **`if err != nil { panic(err) }`:**
44+
- This code checks if an error occurred during the file creation process (which will not happen in this example due to the preceding panic).
45+
- If an error is present, it triggers another panic with the error message.
46+
47+
It's important to note that initiating a panic is typically used in exceptional situations where the program cannot continue normal execution. In general, using panics should be done judiciously, and it's often preferable to handle errors in a more controlled manner using error values and other error-handling techniques.

documentation/46-defer.md

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
This Go code illustrates the use of `defer` statements to ensure that certain actions, like closing a file, are performed even if an error occurs. Let's go through the code with inline comments and explanations:
2+
3+
```go
4+
// Importing necessary packages.
5+
import (
6+
"fmt"
7+
"os"
8+
)
9+
10+
// The main function, where the execution of the program begins.
11+
func main() {
12+
// Creating a file and deferring the closing of the file until the surrounding function returns.
13+
f := createFile("/tmp/defer.txt")
14+
defer closeFile(f)
15+
16+
// Writing data to the file.
17+
writeFile(f)
18+
}
19+
20+
// createFile function creates a file and returns a pointer to the os.File.
21+
func createFile(p string) *os.File {
22+
fmt.Println("creating")
23+
// Attempting to create the file.
24+
f, err := os.Create(p)
25+
if err != nil {
26+
// If an error occurs during file creation, the program panics.
27+
panic(err)
28+
}
29+
return f
30+
}
31+
32+
// writeFile function writes data to the provided os.File.
33+
func writeFile(f *os.File) {
34+
fmt.Println("writing")
35+
// Writing the data to the file.
36+
fmt.Fprintln(f, "data")
37+
}
38+
39+
// closeFile function closes the provided os.File, handling errors.
40+
func closeFile(f *os.File) {
41+
fmt.Println("closing")
42+
// Closing the file and checking for errors.
43+
err := f.Close()
44+
45+
// Handling errors if the file cannot be closed successfully.
46+
if err != nil {
47+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
48+
os.Exit(1)
49+
}
50+
}
51+
```
52+
### Output
53+
```
54+
creating
55+
panic: open /tmp/defer.txt: The system cannot find the path specified.
56+
57+
goroutine 1 [running]:
58+
main.createFile({0x622f83, 0xe})
59+
..:/...../..../..../defer.go:19 +0x93
60+
main.main()
61+
..:/...../..../..../defer.go:10 +0x2b
62+
exit status 2
63+
```
64+
Explanation:
65+
66+
1. **`createFile(p string) *os.File`:**
67+
- This function creates a file at the specified path `p`.
68+
- If an error occurs during file creation, the function panics with the error message.
69+
- The created file is returned as a pointer to `os.File`.
70+
71+
2. **`writeFile(f *os.File)`:**
72+
- This function writes the string "data" to the provided file (`os.File`).
73+
74+
3. **`closeFile(f *os.File)`:**
75+
- This function closes the provided file (`os.File`).
76+
- If an error occurs during file closing, it prints an error message to `os.Stderr` and exits the program.
77+
78+
4. **`defer closeFile(f)`:**
79+
- The `defer` statement ensures that the `closeFile` function is called when the surrounding function (`main` in this case) returns, regardless of whether it returns normally or panics.
80+
- In this example, it ensures that the file is closed even if an error occurs during the execution of `main`.
81+
82+
Using `defer` is a convenient way to ensure that cleanup actions are performed, especially when dealing with resources like files, to avoid resource leaks.

documentation/48-recover.md

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
This Go code demonstrates the use of the `recover` function to catch and handle panics within a deferred function. Let's go through the code with inline comments and explanations:
2+
3+
```go
4+
// Importing necessary package.
5+
import "fmt"
6+
7+
// mayPanic function deliberately panics with a custom error message.
8+
func mayPanic() {
9+
panic("a problem")
10+
}
11+
12+
// The main function, where the execution of the program begins.
13+
func main() {
14+
// Using a deferred anonymous function to recover from panics.
15+
defer func() {
16+
// The recover function is used to catch a panic.
17+
if r := recover(); r != nil {
18+
// Handling the panic by printing the recovered error message.
19+
fmt.Println("Recovered. Error:\n", r)
20+
}
21+
}()
22+
23+
// Calling the mayPanic function, which panics intentionally.
24+
mayPanic()
25+
26+
// This line will be reached only if there is no panic in the mayPanic function.
27+
fmt.Println("After mayPanic()")
28+
}
29+
```
30+
### output
31+
```
32+
Recovered. Error:
33+
a problem
34+
```
35+
36+
Explanation:
37+
38+
1. **`mayPanic()`:**
39+
- This function deliberately panics with the custom error message "a problem."
40+
41+
2. **`defer func() { ... }()`:**
42+
- The `defer` statement is used to schedule the execution of an anonymous function to be performed when the surrounding function (`main` in this case) exits.
43+
- The anonymous function includes a `recover()` call, which returns `nil` if there is no panic or the value passed to `panic` if a panic occurred.
44+
45+
3. **`if r := recover(); r != nil { ... }`:**
46+
- Inside the deferred function, the `recover` function is used to catch a panic.
47+
- If a panic occurred, the recovered value (error message in this case) is printed.
48+
49+
4. **`mayPanic()`:**
50+
- This line calls the `mayPanic` function, which intentionally panics.
51+
52+
5. **`fmt.Println("After mayPanic()")`:**
53+
- If there was no panic or if the panic was recovered successfully, this line will be executed.
54+
- If a panic occurred and was caught by the deferred function, the program will continue executing from this point.
55+
56+
Using `recover` in a deferred function is a common pattern for handling panics and performing cleanup or logging operations before the program exits. It allows you to gracefully recover from unexpected errors and continue with the execution of the program.

documentation/SUMMARY.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,8 @@
4343
* [Atomic Counters](40-atomic-conters.md)
4444
* [Mutexes](41-mutexes.md)
4545
* [Stateful Goroutines](42-stateful-goroutines.md)
46-
* [Sorting](43-sorting.md)
46+
* [Sorting](43-sorting.md)
47+
* [Sorting by Functions](44-sorting-by-functions.md)
48+
* [Panic](45-panic.md)
49+
* [Defer](46-defer.md)
50+
* [Recover](47-recover.md)

0 commit comments

Comments
 (0)