Skip to content

Commit

Permalink
fix conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
tsingbx committed Oct 20, 2023
2 parents 030a243 + eb1f203 commit 5a34b86
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 4 deletions.
27 changes: 27 additions & 0 deletions 208-Defer/defer-1.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// A defer statement defers the execution of a function until the surrounding function returns.
// The deferred call's arguments are evaluated immediately,
// but the function call is not executed until the surrounding function returns.
// Defer is commonly used to simplify functions that perform various clean-up actions.

import (
"io"
"os"
)
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.open(srcName)
if err != nil {
return
}
defer src.close()

dst, err := os.create(dstName)
if err != nil {
return
}
defer dst.close()

return io.copy(dst, src)
}

// Defer statements allow us to think about closing each file right after opening it, guaranteeing that, regardless of the number of return statements in the function, the files will be closed.

9 changes: 9 additions & 0 deletions 208-Defer/defer-2.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Stacking defers

// Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.

println("counting")
for i := 0; i < 10; i++ {
defer println(i)
}
println("done")
1 change: 0 additions & 1 deletion 208-Defer/defer.gop

This file was deleted.

29 changes: 29 additions & 0 deletions 209-Exceptions/exceptions-1.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Panic
// Panic is a built-in function that stops the normal execution flow. When you call panic in your code, it means you’ve decided that your caller can’t solve the problem. Therefore, you should use panic only in rare cases where it’s not safe for your code or anyone integrating your code to continue at that point.
// The code sample below demonstrates how panic works:

import (
"errors"
)

func A() {
defer println("Then we can't save the earth!")
B()
}
func B() {
defer println("And if it keeps getting hotter...")
C()
}
func C() {
defer println("Turn on the air conditioner...")
Break()
}
func Break() {
defer println("If it's more than 30 degrees...")
panic(errors.New("Global Warming!!!"))
println("Goodbye!")
}

A()

// As shown above, when panic is used and not handled, the execution flow stops, all deferred functions are executed in reverse order, and stack traces are printed.
32 changes: 32 additions & 0 deletions 209-Exceptions/exceptions-2.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Recover

// To report an error as a return value, you have to call the recover function in the same goroutine as where the panic function is called, retrieve an error struct from the recover function, and pass it to a variable:

import (
"errors"
)

func saveEarth() (err error) {

defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
TooLate()
return
}

func TooLate() {
A()
panic(errors.New("Then there's nothing we can do"))
}

func A() {
defer println("If it's more than 100 degrees...")
}

err := saveEarth()
println(err)

// Every deferred function will be executed after a function call but before a return statement. Therefore, you can set a returned variable before a return statement is executed.
1 change: 0 additions & 1 deletion 209-Exceptions/exceptions.gop

This file was deleted.

18 changes: 18 additions & 0 deletions 210-Methods/methods-1.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Go+ does not have classes. However, you can define methods on types.
// A method is a function with a special receiver argument.
// The receiver appears in its own argument list between the func keyword and the method name.

import (
"math"
)

type Vertex struct {
X, Y float64
}

func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

v := Vertex{3, 4}
println(v.Abs())
20 changes: 20 additions & 0 deletions 210-Methods/methods-2.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Declare a method on non-struct types

import (
"math"
)

type MyFloat float64

func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}

f := MyFloat(-math.Sqrt2)
println(f.Abs())

// In this example we see a numeric type MyFloat with an Abs method.
// You can only declare a method with a receiver whose type is defined in the same package as the method. You cannot declare a method with a receiver whose type is defined in another package (which includes the built-in types such as int).
1 change: 0 additions & 1 deletion 210-Methods/methods.gop

This file was deleted.

73 changes: 73 additions & 0 deletions 212-Composing-Types-by-Struct-Embedding/struct-emb-1.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Go+ does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface.
// Only interfaces can be embedded within interfaces.
// Only struct can be embedded within struct.

// The Sample has two struct types, Hello struct and Goodbye struct, each of which implements the Talk interface. And HelloGoodbye struct also implements Talk interface, which it does by combining Hello struct and Goodbye struct into one struct using embedding: it lists the types within the struct but does not give them field names.

type Talk interface {
Say()
}

type Hello struct {
name string
}

func (hello *Hello) Say() {
println "Hello ", hello.name
}

func (hello *Hello) Sleep() {
println "Hello ", hello.name, "go to bed!"
}

type Goodbye struct {
name string
}

func (goodbye *Goodbye) Say() {
println "Goodbye ", goodbye.name
}

type Forward struct {
}

func (forward *Forward)Say() {
forward.SayForward()
}

func (forward *Forward) SayForward() {
println "You must forward method!"
}

type HelloGoodbye struct {
*Hello
*Goodbye
forward *Forward
}

func (hg *HelloGoodbye) Say() {
hg.Hello.Say()
hg.Goodbye.Say()
hg.forward.Say()
}

helloGoodbye := HelloGoodbye{
&Hello{"tsingbx"},
&Goodbye{"tsingbx"},
&Forward{},
}
helloGoodbye.Say()
println()
helloGoodbye.Sleep()
println()
helloGoodbye.forward.SayForward()

// The embedded elements are pointers to structs and of course must be initialized to point to valid structs before they can be used.

// The HelloGoodbye struct also have forward member written as forward *Forward, but then to promote the methods of the forward and to satisfy the Talk interface, we would also need to provide forwarding methods, like this: hg.forward.Say(). By embedding the structs directly, we avoid this bookkeeping. The methods of embedded types come along for free, which means that HelloGoodbye struct also has the methods of Hello struct and Goodbye struct.

// There's an important way in which embedding differs from subclassing. When we embed a type, the methods of that type become methods of the outer type, but when they are invoked the receiver of the method is the inner type, not the outer one. In our example, when the Sleep method of a HelloGoodbye is invoked, it has exactly the same effect as the forwarding method helloGoodbye.Hello.Sleep(); the receiver is the helloGoodbye.Hello, not the helloGoodbye itself.




34 changes: 34 additions & 0 deletions 212-Composing-Types-by-Struct-Embedding/struct-emb-2.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Embedding can also be a simple convenience.
// This example shows an embedded field alongside a regular, named field.

import "log"
import "fmt"
import "os"

type Job struct {
Command string
*log.Logger
}

func (job *Job) Printf(format string, args ...interface{}) {
job.Logger.Printf("%q: %s", job.Command, fmt.Sprintf(format, args...))
}

func NewJob(command string, logger *log.Logger) *Job {
return &Job{command, logger}
}

job := &Job{"cmd", log.New(os.Stderr, "Job: ", log.Ldate)}
job.Println("starting now...")
job.Printf("format string %d", 1)

// The Job type now has the Print, Printf, Println and other methods of *log.Logger. We could have given the Logger a field name, of course, but it's not necessary to do so. And now, once initialized, we can log to the Job: job.Println("starting now...")

// The Logger is a regular field of the Job struct, so we can initialize it in the usual way inside the constructor for Job, like function NewJob do, or with a composite literal, job := &Job{command, log.New(os.Stderr, "Job: ", log.Ldate)}

// If we need to refer to an embedded field directly, the type name of the field, ignoring the package qualifier, serves as a field name, as it did in the Printf method of our Job struct. Here, if we needed to access the *log.Logger of a Job variable job, we would write job.Logger, which would be useful if we wanted to refine the methods of Logger.

// Embedding types introduces the problem of name conflicts but the rules to resolve them are simple. First, a field or method X hides any other item X in a more deeply nested part of the type. If log.Logger contained a field or method called Command, the Command field of Job would dominate it.

// Second, if the same name appears at the same nesting level, it is usually an error; it would be erroneous to embed log.Logger if the Job struct contained another field or method called Logger. However, if the duplicate name is never mentioned in the program outside the type definition, it is OK. This qualification provides some protection against changes made to types embedded from outside; there is no problem if a field is added that conflicts with another field in another subtype if neither field is ever used.

1 change: 0 additions & 1 deletion 212-Composing-Types-by-Struct-Embedding/struct-emb.gop

This file was deleted.

0 comments on commit 5a34b86

Please sign in to comment.