1. Write the following code output
package main import ( "fmt" ) func main() { defer_call() } func defer_call() {
defer func() { fmt.Println(" Before printing ") }() defer func() { fmt.Println(" Printing ") }()
defer func() { fmt.Println(" After printing ") }() panic(" Trigger exception ") }
In this case , In fact, the order in which the words "trigger exception" are printed is uncertain .defer, panic, recover It is usually used together to catch exceptions . Let's take a look at the following case :

* Case 1 package main import ( "fmt" ) func main() { defer_call() } func
defer_call() { defer func() { fmt.Println(" Before printing ") }() defer func() {
fmt.Println(" Printing ") }() defer func() { // It has to be stated first defer, otherwise recover() Cannot capture panic abnormal if
err := recover();err != nil { fmt.Println(err) //err namely panic Parameters passed in }
fmt.Println(" After printing ") }() panic(" Trigger exception ") }
The output content is :
Trigger exception After printing Printing Before printing Process finished with exit code 0
* Case 2 package main import ( "fmt" ) func main() { defer_call() } func
defer_call() { defer func() { fmt.Println(" Before printing ") }() defer func() { //
It has to be stated first defer, otherwise recover() Cannot capture panic abnormal if err := recover();err != nil {
fmt.Println(err) //err namely panic Parameters passed in } fmt.Println(" Printing ") }() defer func() {
fmt.Println(" After printing ") }() panic(" Trigger exception ") }
The output content is :
After printing Trigger exception Printing Before printing Process finished with exit code 0
* Case 3 package main import ( "fmt" ) func main() { defer_call() } func
defer_call() { defer func() { if err := recover();err != nil { fmt.Println(err)
//err namely panic Parameters passed in } fmt.Println(" Before printing ") }() defer func() { //
It has to be stated first defer, otherwise recover() Cannot capture panic abnormal if err := recover();err != nil {
fmt.Println(err) //err namely panic Parameters passed in } fmt.Println(" Printing ") }() defer func() { if
err := recover();err != nil { fmt.Println(err) //err namely panic Parameters passed in }
fmt.Println(" After printing ") }() panic(" Trigger exception ") }
The output content is :
Trigger exception After printing Printing Before printing Process finished with exit code 0
summary :

* defer The function belongs to delay execution , Delay to caller function execution  return  The command is executed before it is executed . Multiple defer Press between LIFO FIFO sequence execution .
* Go You can throw a panic The anomaly of , And then in the defer Passed in recover Catch this exception , And then deal with it normally .
* If there are more than one defer, Then the exception will be replaced by the nearest one recover() Capture and process normally .
<>2. What's wrong with the following code , Explain why
package main import ( "fmt" ) type student struct { Name string Age int } func
pase_student() map[string]*student { m := make(map[string]*student) stus :=
[]student{ {Name: "zhou", Age: 24}, {Name: "li", Age: 23}, {Name: "wang", Age:
22}, } for _, stu := range stus { m[stu.Name] = &stu } return m } func main() {
students := pase_student() for k, v := range students {
fmt.Printf("key=%s,value=%v \n", k, v) } }
Running results :
key=zhou,value=&{wang 22} key=li,value=&{wang 22} key=wang,value=&{wang 22}
Process finished with exit code 0
Change the code :

Add the following code :
for _, stu := range stus { m[stu.Name] = &stu }
Amend to read :
for _, stu := range stus { fmt.Printf("%v\t%p\n",stu,&stu) m[stu.Name] = &stu }
The running results are as follows :
{shen 24} 0xc4200a4020 {li 23} 0xc4200a4020 {wang 22} 0xc4200a4020
key=shen,value=&{wang 22} key=li,value=&{wang 22} key=wang,value=&{wang 22}
Process finished with exit code 0
Through the above case , It's not hard to find out stu The address of the variable is always the same , Each traversal only takes place struct Value copy , so m[stu.Name]=&stu
It's actually pointing to the same address all the time , Finally, the value of this address is the last one traversed struct Value copy of .

It is the same as the following code :
var stu student for _, stu = range stus { m[stu.Name] = &stu }
Amendment plan , Take the address of the original value in the array :
for i, _ := range stus { stu:=stus[i] m[stu.Name] = &stu }
Rerun , The effect is as follows :
{shen 24} 0xc42000a060 {li 23} 0xc42000a0a0 {wang 22} 0xc42000a0e0
key=shen,value=&{shen 24} key=li,value=&{li 23} key=wang,value=&{wang 22}
Process finished with exit code 0
<>3. What does the following code output , And explain the reason
package main import ( "fmt" "runtime" "sync" ) func init() {
fmt.Println("Current Go Version:", runtime.Version()) } func main() {
runtime.GOMAXPROCS(1) count := 10 wg := sync.WaitGroup{} wg.Add(count * 2) for
i := 0; i < count; i++ { go func() { fmt.Printf("[%d]", i) wg.Done() }() } for
i := 0; i < count; i++ { go func(i int) { fmt.Printf("-%d-", i) wg.Done() }(i)
} wg.Wait() }
Operation effect :
Current Go Version: go1.10.1
-9-[10][10][10][10][10][10][10][10][10][10]-0--1--2--3--4--5--6--7--8- Process
finished with exit code 0
Two for Inside the cycle go func  Call parameters i It's different , The result is totally different . This is also a common pitfall for novices .

first go func in i It's the outside for A variable of , The address does not change . After traversal , final i=10. so go func On execution ,i The value of is always 10(10 The second traversal is done quickly ).

the second go func in i Is a function parameter , With the outside world for In i It's two variables . tail (i) The value copy will occur ,go func Internal point value copy address .

<>4. What does the following code output ?
package main import "fmt" type People struct{} func (p *People) ShowA() {
fmt.Println("showA") p.ShowB() } func (p *People) ShowB() {
fmt.Println("showB") } type Teacher struct { People } func (t *Teacher) ShowB()
{ fmt.Println("teacher showB") } func main() { t := Teacher{} t.ShowA() }
The results are as follows :
showA showB Process finished with exit code 0
Go There is no inheritance in the book , The above writing method is called combination .

above t.ShowA() Equivalent to t.People.ShowA(), The above code will be modified as follows :
func main() { t := Teacher{} t.ShowA() fmt.Println("---------------")
t.People.ShowA() }
The running results are as follows :
showA showB --------------- showA showB Process finished with exit code 0
<>5. Will the following code trigger an exception ? Please elaborate
package main func main() { runtime.GOMAXPROCS(1) int_chan := make(chan int, 1)
string_chan := make(chan string, 1) int_chan <- 1 string_chan <- "hello" select
{ case value := <-int_chan: fmt.Println(value) case value := <-string_chan:
panic(value) } }
There is a possibility of anomalies , without selct This is the code , There will be thread blocking , When there is selct After this statement , The system will randomly select one case Make a judgment , Only one of the statements works
return, This program will be executed immediately .

<>6. What does the following code output ?
package main import "fmt" func calc(index string, a, b int) int { ret := a + b
fmt.Println(index, a, b, ret) return ret } func main() { a := 1 b := 2 defer
calc("1", a, calc("10", a, b)) a = 0 defer calc("2", a, calc("20", a, b)) b = 1
}
The results are as follows :
10 1 2 3 20 0 2 2 2 0 2 2 1 1 3 4 Process finished with exit code 0
Two concepts need to be clear before solving the problem :

* defer Is at the end of the function return Pre implementation , Implementation after advance .
* Function call  int  Parameter value copy .
Regardless of the order of the code ,defer calc func Medium parameter b It has to be calculated first , So when you run to the third line , implement calc("10",a,b) output :10 1 2 3 Get the value 3, take
cal("1",1,3) Put it in the queue of deferred execution function .

At the fifth line , Current calculation calc("20", a, b) Namely calc("20", 0, 2) output :20 0 2 2 Get the value 2, take cal("2",0,2)
To the queue of deferred functions .

Execute to the last line , According to the principle of "first in, last out" in the queue :cal("2",0,2),cal("1",1,3), Output in turn :2 0 2 2,1 1 3 4 .

<>7. Please write the following input
package main import "fmt" func main() { s := make([]int, 5) fmt.Printf("%p\n",
s) s = append(s, 1, 2, 3) fmt.Printf("%p\n", s) //new pointer fmt.Println(s) }
Running results :
0xc4200180c0 0xc42001c0a0 [0 0 0 0 0 1 2 3] Process finished with exit code 0
<>8. What's wrong with the following code
package main import ( "fmt" "sync" ) type UserAges struct { ages
map[string]int sync.Mutex } func (ua *UserAges) Add(name string, age int) {
ua.Lock() defer ua.Unlock() ua.ages[name] = age } func (ua *UserAges) Get(name
string) int { if age, ok := ua.ages[name]; ok { return age } return -1 } func
main() { count := 1000 gw := sync.WaitGroup{} gw.Add(count * 3) u :=
UserAges{ages: map[string]int{}} add := func(i int) {
u.Add(fmt.Sprintf("user_%d", i), i) gw.Done() } for i := 0; i < count; i++ { go
add(i) go add(i) } for i := 0; i < count; i++ { go func(i int) { defer
gw.Done() u.Get(fmt.Sprintf("user_%d", i)) }(i) } gw.Wait() fmt.Println("Done")
}
Output results :
fatal error: concurrent map read and map write goroutine 2022 [running]:
runtime.throw(0x10c5472, 0x21)
conclusion :  In execution  Get  Method may be used panic.

Although there is use sync.Mutex Write lock , however map It is unsafe to read and write concurrently .map
Belongs to the reference type , When reading and writing concurrently, multiple cooperators access the same address through pointers , Access to shared variables , At this time, there is a competitive relationship between simultaneous reading and writing resources . So it will report an error message :fatal error:
concurrent map read and map write.

If it doesn't reappear for the first time panic problem , It can be run again , Repeat the question . So how to improve it ? stay Go1.9 The new version will provide concurrent security map. First, you need to understand the differences between the two locks :

* sync.Mutex mutex
* sync.RWMutex Read write lock , Implementation of mutual exclusive lock , You can add multiple read locks or one write lock .
RWMutex correlation method :
type RWMutex func (rw *RWMutex) Lock() func (rw *RWMutex) RLock() func (rw
*RWMutex) RLocker() Locker func (rw *RWMutex) RUnlock() func (rw *RWMutex)
Unlock()
The code is improved as follows :
package main import ( "fmt" "sync" ) type UserAges struct { ages
map[string]int sync.RWMutex } func (ua *UserAges) Add(name string, age int) {
ua.Lock() defer ua.Unlock() ua.ages[name] = age } func (ua *UserAges) Get(name
string) int { ua.RLock() defer ua.RUnlock() if age, ok := ua.ages[name]; ok {
return age } return -1 } func main() { count := 10000 gw := sync.WaitGroup{}
gw.Add(count * 3) u := UserAges{ages: map[string]int{}} add := func(i int) {
u.Add(fmt.Sprintf("user_%d", i), i) gw.Done() } for i := 0; i < count; i++ { go
add(i) go add(i) } for i := 0; i < count; i++ { go func(i int) { defer
gw.Done() u.Get(fmt.Sprintf("user_%d", i)) fmt.Print(".") }(i) } gw.Wait()
fmt.Println("Done") }
The results are as follows :
. . Done Process finished with exit code 0
<>9. What's wrong with the next iteration ?
package main import "fmt" import "sync" import "time" type ThreadSafeSet
struct { sync.RWMutex s []int } func (set *ThreadSafeSet) Iter() <-chan
interface{} { ch := make(chan interface{}) go func() { set.RLock() for elem :=
range set.s { ch <- elem fmt.Print("get:", elem, ",") } close(ch) set.RUnlock()
}() return ch } func main() { //read() unRead() } func read() { set :=
ThreadSafeSet{} set.s = make([]int, 100) ch := set.Iter() closed := false for {
select { case v, ok := <-ch: if ok { fmt.Print("read:", v, ",") } else { closed
= true } } if closed { fmt.Print("closed") break } } fmt.Print("Done") } func
unRead() { set := ThreadSafeSet{} set.s = make([]int, 100) ch := set.Iter() _ =
ch time.Sleep(5 * time.Second) fmt.Print("Done") }
conclusion : The internal iteration is blocked . No buffer at default initialization , You need to wait for the receiver to read before writing .

chan in use make An optional parameter can be attached to the initialization to set the buffer . No buffer by default , The topic is initialized without buffer chan, In this way, only the written element can continue to write until it is read , Otherwise, it will be blocked all the time .

After setting the buffer size , When writing data, it can be continuously written to the buffer , Until the buffer is full . from chan Receive once in to release once from the buffer . It can be understood as chan It is a processing pool where throughput can be set .

ch := make(chan interface{}) and  ch := make(chan interface{},1) It's different
Unbuffered It's not just about asking  ch  Channel discharge One value It's about being accepted all the time , that ch <- elem
Will continue , Or it'll be blocked all the time , That is to say, only when there is a receiver , Blocking without a receiver .

The buffer is 1 Even if there is no receiver, it will not block , Because the buffer size is 1 Only when When you put the second value The first one hasn't been taken , That's when it gets blocked

<>10. Can the following code be compiled ? Why? ?
package main import ( "fmt" ) type People interface { Speak(string) string }
type Stduent struct{} func (stu *Stduent) Speak(think string) (talk string) {
if think == "bitch" { talk = "You are a good boy" } else { talk = "hi" } return
} func main() { var peo People = Stduent{} think := "bitch"
fmt.Println(peo.Speak(think)) }
conclusion : Compilation failed , Value type  Student{}  Interface not implemented People How to do it , Cannot be defined as  People  type .

Two correct modification methods :

* Method 1 package main import ( "fmt" ) type People interface { Speak(string)
string } type Stduent struct{} func (stu Stduent) Speak(think string) (talk
string) { if think == "bitch" { talk = "You are a good boy" } else { talk =
"hi" } return } func main() { var peo People = Stduent{} think := "hi"
fmt.Println(peo.Speak(think)) }
* Method 2 package main import ( "fmt" ) type People interface { Speak(string)
string } type Stduent struct{} func (stu Stduent) Speak(think string) (talk
string) { if think == "bitch" { talk = "You are a good boy" } else { talk =
"hi" } return } func main() { var peo People = &Stduent{} think := "bitch"
fmt.Println(peo.Speak(think)) }
summary : Pointer type struct objects can call methods corresponding to struct value type and pointer type at the same time . The structure object of value type can only call the interface method corresponding to value type .

Technology