Golang interview questions analysis

Recently, I have seen the interview questions of golang in many places , and I have seen that many people are afraid of the interview questions of golang. It is also to review the basics. I summarize the process of solving the problem.

interview questions

1. Write the output of the following code.


package main

import (
    "fmt"
)

func main() {
    defer_call()
}

func defer_call() {
    defer func() { fmt.Println("打印前") }()
    defer func() { fmt.Println("打印中") }()
    defer func() { fmt.Println("打印后") }()

    panic("触发异常")
}

Test site: defer execution order
Answer:
defer is last in, first out .
Panic needs to wait until defer ends before being passed up. When panic occurs, it will be executed in the last-in-first-out order of defer, and then panic will be executed last.

打印后
打印中
打印前
panic: 触发异常

Recently, some students have found that panicthe execution order is not certain when they encounter multiple executions. Is it because there panicis deferno sequential relationship? Let's start with the following example:

func main() {
	defer_call()
}

func defer_call() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("one=", err)
		}
	}()
	defer func() { fmt.Println("打印前") }()
	defer func() { fmt.Println("打印中") }()
	defer func() { fmt.Println("打印后") }()

	panic("触发异常")

}

Let’s execute it multiple times to see if it is all output:

打印后
打印中
打印前
one= 触发异常

Then why is there no additional recover()time, and the panic execution order is not determined? The execution order of defer is definitely FILO, but the panic coroutine (thread) that has not been recovered may compete for the CPU faster than defer, so this situation may also be a write cache problem, so recover the panic. Add to the defer queue.

2. What is wrong with the following code and explain why.

type student struct {
    Name string
    Age  int
}

func pase_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
    }

}

Test site: foreach
Answer:
Beginners will often encounter this way of writing, and it is very dangerous! Like Java's foreach, it uses a copy method. So m[stu.Name]=&stu actually points to the same pointer, and finally the value of the pointer is a copy of the value of the last struct traversed. Like wanting to modify the properties of the sliced ​​element:

for _, stu := range stus {
    stu.Age = stu.Age+10
}

is also not feasible. You can try printing it out:

func pase_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
    }

    for k,v:=range m{
        println(k,"=>",v.Name)
    }

    // 正确
    for i:=0;i<len(stus);i++  {
        m[stus[i].Name] = &stus[i]
    }
    for k,v:=range m{
        println(k,"=>",v.Name)
    }
}

3. What will the following code output and why

func main() {
    runtime.GOMAXPROCS(1)
    wg := sync.WaitGroup{}
    wg.Add(20)
    for i := 0; i < 10; i++ {
        go func() {
            fmt.Println("A: ", i)
            wg.Done()
        }()
    }
    for i := 0; i < 10; i++ {
        go func(i int) {
            fmt.Println("B: ", i)
            wg.Done()
        }(i)
    }
    wg.Wait()
}

Test site: Randomness and closure of go execution
Answer:
No one knows what the order of printing is after execution, so it can only be said that it is a random number. But they A:all output 10, B:from 0 to 9 (the order is uncertain). In the first go func, i is a variable of the outer for, and the address does not change. After the traversal is completed, the final i=10. Therefore, when go func is executed, the value of i is always 10.

i in the second go func is a function parameter, and i in the outer for is exactly two variables. The tail (i) will copy the value, and the go func internally points to the address of the value copy.

4. What will the following code output?

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()
}

Test site: Go's compositional inheritance
Answer:
This is Golang's compositional mode, which can implement OOP inheritance. Although the methods contained in the combined type People are upgraded to the methods of the combined type of the external type Teacher (it must be an anonymous field), the receiver does not change when their method (ShowA()) is called. At this time, the People type does not know what type it will be combined with, and of course it cannot use the unknown combiner Teacher type function when calling the method.

showA
showB

5. Will the following code trigger an exception? Please explain in details

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)
    }
}

Test site: select randomness
Answer:
select will randomly select an available universal for sending and receiving operations. So the code is willing to trigger an exception, or it may not. A single chan will block if unbuffered. But combined with select, you can wait for execution between multiple chans. There are three principles:

  • As long as there is one case in select that can return, it will be executed immediately.
  • When multiple cases can return at the same time, any one of them is selected and executed in a pseudo-random manner.
  • If none of the cases can return then the "default" block can be executed.

6. What is the output of the following code?

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
}

Test site: defer execution order
Answer:
This question is similar to question 1. It should be noted that defer execution order and value transfer index: 1 must be executed last, but the third parameter of index: 1 is a function, so it is called first calc("10",1,2)==>10,1,2,3 When executing index:2, as before, you need to call calc("20",0,2)==>20,0, 2,2 Start to call when b=1 is executed, index:2==>calc("2",0,2)==>2,0,2,2 Finally execute index:1==>calc("1 ",1,3)==>1,1,3,4

10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4

7. Please write the following input

func main() {
    s := make([]int, 5)
    s = append(s, 1, 2, 3)
    fmt.Println(s)
}

Test site: make default value and append
Answer:
make initialization is by default value, here the default value is 0

[0 0 0 0 0 1 2 3]

Try changing it to:

s := make([]int, 0)
s = append(s, 1, 2, 3)
fmt.Println(s)//[1 2 3]

8. What's wrong with the code below?

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
}

Test site: map thread safety
Answer:
It may appear fatal error: concurrent map read and map write. Modify it to see the effect

func (ua *UserAges) Get(name string) int {
    ua.Lock()
    defer ua.Unlock()
    if age, ok := ua.ages[name]; ok {
        return age
    }
    return -1
}

9. What's wrong with the next iteration?

func (set *threadSafeSet) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go func() {
		set.RLock()

		for elem := range set.s {
			ch <- elem
		}

		close(ch)
		set.RUnlock()

	}()
	return ch
}

Test site: chan buffer pool
Answer:
Seeing this question, I am also guessing where the intention of the questioner is. chan?sync.RWMutex?go?chan buffer pool?iteration? Since it is an iteration, all set.s can be traversed once. But chan is cached, which means that the write will block once. Let's restore the code to a runnable way and see the effect

package main

import (
    "sync"
    "fmt"
)

//下面的迭代会有什么问题?

type threadSafeSet struct {
    sync.RWMutex
    s []interface{}
}

func (set *threadSafeSet) Iter() <-chan interface{} {
    // ch := make(chan interface{}) // 解除注释看看!
    ch := make(chan interface{},len(set.s))
    go func() {
        set.RLock()

        for elem,value := range set.s {
            ch <- elem
            println("Iter:",elem,value)
        }

        close(ch)
        set.RUnlock()

    }()
    return ch
}

func main()  {

    th:=threadSafeSet{
        s:[]interface{}{"1","2"},
    }
    v:=<-th.Iter()
    fmt.Sprintf("%s%v","ch",v)
}

10. Can the following code compile? 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))
}

Test site: Golang method set
Answer: The
compilation fails! make a mistake! ? It means that you still have some questions about golang's method set. In a word: golang's method set only affects interface implementation and method expression conversion, and has nothing to do with calling methods through instances or pointers.

11. What does the following code print out and why.

package main

import (
	"fmt"
)

type People interface {
	Show()
}

type Student struct{}

func (stu *Student) Show() {

}

func live() People {
	var stu *Student
	return stu
}

func main() {
	if live() == nil {
		fmt.Println("AAAAAAA")
	} else {
		fmt.Println("BBBBBBB")
	}
}

Test site: interface internal structure
Answer:
very classic question! This test site is the internal structure of the interface that many people ignore. Interfaces in go are divided into two types: one is an empty interface like this:

var in interface{}

Another such topic:

type People interface {
    Show()
}

Their underlying structure is as follows:

type eface struct {      //空接口
    _type *_type         //类型信息
    data  unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)
}
type iface struct {      //带有方法的接口
    tab  *itab           //存储type信息还有结构实现方法的集合
    data unsafe.Pointer  //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)
}
type _type struct {
    size       uintptr  //类型大小
    ptrdata    uintptr  //前缀持有所有指针的内存大小
    hash       uint32   //数据hash值
    tflag      tflag
    align      uint8    //对齐
    fieldalign uint8    //嵌入结构体时的对齐
    kind       uint8    //kind 有些枚举值kind等于0是无效的
    alg        *typeAlg //函数指针数组,类型实现的所有方法
    gcdata    *byte
    str       nameOff
    ptrToThis typeOff
}
type itab struct {
    inter  *interfacetype  //接口类型
    _type  *_type          //结构类型
    link   *itab
    bad    int32
    inhash int32
    fun    [1]uintptr      //可变大小 方法集合
}

It can be seen that iface has one more itab structure than eface. itab stores _type information and []fun method set. From the above structure, we can conclude that because data points to nil, it does not mean that the interface is nil, so the return value is not empty. The definition of fun (method set) here In order to understand the receiving rules of the interface, it is necessary to verify whether the interface result is implemented during the compilation process:

BBBBBBB

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325457876&siteId=291194637