page contents

Golang经典面试题+答案,建议收藏

1.下面代码输出什么,为什么 //make([]T, length, capacity) s1 := []int{1, 2, 3} fmt.Println(s1, "哈哈") //[1 2 3] s2 := s1 fmt.Println(s1, "哈哈") //[1 2 3] for i := 0; i &l...

attachments-2021-05-uEvEKJu96094aa47de3fd.png

1.下面代码输出什么,为什么

	//make([]T, length, capacity)
	s1 := []int{1, 2, 3}
	fmt.Println(s1, "哈哈") //[1 2 3]
	s2 := s1
	fmt.Println(s1, "哈哈") //[1 2 3]
	for i := 0; i < 3; i++ {
		s2[i] = s2[i] + 1
	}
	fmt.Println(s1) //[2 3 4]
	fmt.Println(s2) //[2 3 4]
[1 2 3] 哈哈
[1 2 3] 哈哈
[2 3 4]
[2 3 4]

注:引用就是同一份,相当于起了一个别名,就是多起了一个名字而已。

Go语言中的引用类型有:映射(map),数组切片(slice),通道(channel),方法与函数。

整型,字符串,布尔,数组在当作参数传递时,是传递副本的内存地址,也就是值传递。

2.下面代码输出什么,为什么

func rmLast(a []int) {
	fmt.Println("a", a)
	a = a[:len(a)-1]
	for i := 0; i < 13; i++ {
		a = append(a, 8)
	}
	fmt.Println("rm后a", a)
	// fmt.Println(len(a))
}
func updateLast(a []int) {
	fmt.Println("a", a)
	for i := 0; i < len(a); i++ {
		a[i] = a[i] + 1
	}
	fmt.Println("修改后a", a)
	// fmt.Println(len(a))
}
func main() {
	xyz := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println("xyz", xyz)
	rmLast(xyz)
	fmt.Println("rm后xyz", xyz)
	updateLast(xyz)
	fmt.Println("修改后xyz", xyz) //[1 2 3 4 5 6 7 8 9]
}
xyz [1 2 3 4 5 6 7 8 9]
a [1 2 3 4 5 6 7 8 9]
rm后a [1 2 3 4 5 6 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8]
rm后xyz [1 2 3 4 5 6 7 8 8]
a [1 2 3 4 5 6 7 8 8]
修改后a [2 3 4 5 6 7 8 9 9]
修改后xyz [2 3 4 5 6 7 8 9 9]

注:函数内改切片的值,外部是可见的,改切片的长度外部是不可见的

3.下面代码输出什么,为什么

//n1是n2的底层数组
n1 := [3]int{1, 2, 3}
n2 := n1[0:3]
fmt.Println("下面是n1地址 ")
for i := 0; i < len(n1); i++ {
fmt.Printf("%p\n", &n1[i])
}
fmt.Println(n1)
fmt.Println("下面是n2地址  ")
for i := 0; i < len(n2); i++ {
fmt.Printf("%p\n", &n2[i])
}
fmt.Println(n2)
n2 = append(n2, 1)
fmt.Println("下面是n1地址  ")
for i := 0; i < len(n1); i++ {
fmt.Printf("%p\n", &n1[i])
}
fmt.Println(n1)
fmt.Println("下面是n2地址  ")
for i := 0; i < len(n2); i++ {
fmt.Printf("%p\n", &n2[i])
}
fmt.Println(n2)
下面是n1地址 
0xc000064140  
0xc000064148  
0xc000064150  
[1 2 3]       
下面是n2地址  
0xc000064140  
0xc000064148
0xc000064150
[1 2 3]
下面是n1地址
0xc000064140
0xc000064148
0xc000064150
[1 2 3]
下面是n2地址
0xc000090030
0xc000090038
0xc000090040
0xc000090048
[1 2 3 1]

4.下面代码输出什么,为什么

func defer_call(y int) {
for i := 0; i < 5; i++ {
defer fmt.Println("输出y+i", y+i)
fmt.Println("哈哈")
defer fmt.Println("输出i ", i)
}
}
func main() {
defer_call(5)
}
哈哈
哈哈
哈哈
哈哈
哈哈
输出i  4
输出y+1 9
输出i  3
输出y+1 8
输出i  2
输出y+1 7
输出i  1
输出y+1 6
输出i  0
输出y+1 5
注:先执行"哈哈",
退出defer_call这个函数时,反序执行以下函数
fmt.Println("输出y+i",5)
fmt.Println("i",0)
fmt.Println("输出y+i",6)
fmt.Println(....)
fmt.Println("输出y+i",9)
fmt.Println("i",4)

5.下面代码输出什么

func main() {
for i := 0; i < 5; i++ {
fmt.Println(i, "haha")
//匿名函数:匿名函数可以在声明后调用
go func() {
time.Sleep(3 * time.Second)
fmt.Println(i, "嗯嗯")
}()
}
time.Sleep(10 * time.Second)
}
0 haha
1 haha
2 haha
3 haha
4 haha
5 嗯嗯
5 嗯嗯
5 嗯嗯
5 嗯嗯
5 嗯嗯

6.下面代码输出什么

func main() {
strs := []string{"one", "two", "three"}
for _, s := range strs {
//1.主线程都快结束了(主线程跑到three了),并发出来的线程才刚开始
//2.这里匿名函数不传参的话,是共享的s的地址,所以打印出来的都是three
go func() {
time.Sleep(1 * time.Second)
fmt.Printf("%s ", s)
}()
}
time.Sleep(3 * time.Second)
}
three three three

7.下面代码输出什么

func main() {
strs := []string{"one", "two", "three"}
for _, s := range strs {
go func(s string) {
time.Sleep(1 * time.Second)
fmt.Printf("%s ", s)
}(s)
}
time.Sleep(3 * time.Second)
}
three one two
one two three
one three two

注:并发出来三个线程,哪个先结束不一定,所以输出不固定

8.下面代码输出什么

func main() {
x := []string{"ha", "b", "c"}
for v := range x {
fmt.Print(v)
}
}
012

9.下面代码输出什么

type Slice []int
func NewSlice() Slice {
return make(Slice, 0)
}
func (s *Slice) Add(elem int) *Slice {
*s = append(*s, elem)
fmt.Print(elem)
return s
}
func main() {
s := NewSlice()
defer s.Add(1).Add(2)
s.Add(3)
}
132

注:一个defer只能延迟调用一个函数,defer s.Add(1).Add(2),先执行参数部分,然后再延迟调用Add(2)

10.下面代码输出什么

package main
import (
"fmt"
)
func main() {
defer_call()
}
func defer_call() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()
panic("触发异常")
}

考点:defer执行顺序

解答:

defer 是后进先出。

panic 需要等defer 结束后才会向上传递。 出现panic恐慌时候,会先按照defer的后入先出的顺序执行,最后才会执行panic。

打印后

打印中

打印前

panic: 触发异常

11.下面代码输出什么

package main
import (
"fmt"
)
// 遍历切片的每个元素, 通过给定函数进行元素访问
func visit(list []int, f func(int)) {
for _, v := range list {
f(v)
}
}
func main() {
// 使用匿名函数打印切片内容
visit([]int{1, 2, 3, 4}, func(v int) {
fmt.Println(v)
})
}

12.下面代码输出什么

package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
//GOMAXPROCS设置可同时执行的最大CPU数,并返回先前的设置。
// 若 n < 1,它就不会更改当前设置。本地机器的逻辑CPU数可通过 NumCPU 查询。
//本函数在调度程序优化后会去掉。
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()
}

考点:go执行的随机性和闭包

解答:

谁也不知道执行后打印的顺序是什么样的,所以只能说是随机数字。 但是A:均为输出10,B:从0~9输出(顺序不定)。 第一个go func中i是外部for的一个变量,地址不变化。遍历完成后,最终i=10。 故go func执行时,i的值始终是10。

第二个go func中i是函数参数,与外部for中的i完全是两个变量。 尾部(i)将发生值拷贝,go func内部指向值拷贝地址。

13.下面代码输出什么

package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
//GOMAXPROCS设置可同时执行的最大CPU数,并返回先前的设置。
// 若 n < 1,它就不会更改当前设置。本地机器的逻辑CPU数可通过 NumCPU 查询。
//本函数在调度程序优化后会去掉。
runtime.GOMAXPROCS(2)
wg := sync.WaitGroup{}
wg.Add(3)
for i := 0; i < 10; i++ { //主线程
go func() { //并发出来的线程
fmt.Println("A: ", i)
wg.Done()
}()
}
wg.Wait()
wg.Add(7)
wgg := sync.WaitGroup{}
wgg.Add(5)
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println("B: ", i)
wgg.Done()
}(i)
}
wgg.Wait()
}

14.下面代码会触发异常吗?请详细说明

package main
import (
"fmt"
"runtime"
)
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)
    }
}

考点:select随机性

解答:

select会随机选择一个可用通用做收发操作。 所以代码是有肯触发异常,也有可能不会。 单个chan如果无缓冲时,将会阻塞。但结合 select可以在多个chan间等待执行。有三点原则:

select 中只要有一个case能return,则立刻执行。

当如果同一时间有多个case均能return则伪随机方式抽取任意一个执行。

如果没有一个case能return则可以执行”default”块。

15.下面代码有什么问题,如何修改

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() {
var userAges UserAges
userAges.Add("lisa", 24)
userAges.Get("lisa")
fmt.Println(userAges.ages)
}
panic: assignment to entry in nil map
goroutine 1 [running]:
main.(*UserAges).Add(0xc0000521c0, 0x4c492f, 0x4, 0x18)
C:/Users/zyq/go/src/yj/ra.go:17 +0x98
main.main()
C:/Users/zyq/go/src/yj/ra.go:28 +0x69
exit status 2

修改后:

func (ua *UserAges) Add(name string, age int) {
ua.ages = make(map[string]int)
ua.Lock()
defer ua.Unlock()
ua.ages[name] = age
}

输出结果:

map[lisa:24]

16.下面代码输出什么,为什么

package main
import (
"fmt"
"sync"
)
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 := range set.s {
ch <- elem
fmt.Println("Iter:", elem)
}
close(ch)
set.RUnlock()
}()
return ch
}
func main() {
th := threadSafeSet{
s: []interface{}{"1", "2"},
}
v := <-th.Iter()
fmt.Println(v)
}

Iter: 1

Iter: 2

解答:ch := make(chan interface{}, len(set.s)) 每次都会分配一个新的channel,v := <-th.Iter()只传了一个值,所以v是数组s的第一个value

17.以下代码输出什么?为什么?

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

输出:

BBBBBBB

18.以下代码输出什么?为什么?

package main
func main() {
i := GetValue()
switch i.(type) {
case int:
println("int")
case string:
println("string")
case interface{}:
println("interface")
default:
println("unknown")
}
}
func GetValue() int {
return 1
}

解析

考点:type

编译失败,因为type只能使用在interface

修改后:

package main
func main() {
	i := GetValue()
	switch i.(type) {
	case int:
		println("int")
	case string:
		println("string")
	case interface{}:
		println("interface")
	default:
		println("unknown")
	}
}
func GetValue() interface{} {
	return 1
}
package main
func main() {
i := GetValue()
switch i.(type) {
case int:
println("int")
case string:
println("string")
case interface{}:
println("interface")
default:
println("unknown")
}
}
func GetValue() interface{} {
return 1
}

19.以下代码输出什么?为什么?

package main
import "fmt"
func main() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5}
s1 = append(s1, s2...)
fmt.Println(s1)
fmt.Println(s2)
var a = []int{1, 2, 3}
a = append([]int{0}, a...)
fmt.Println(a)
a = append([]int{-3, -2, -1}, a...)
fmt.Println(a)
}

[1 2 3 4 5]

[4 5]

[0 1 2 3]

[-3 -2 -1 0 1 2 3]

考点:

1.追加一个切片, 切片需要解包s1 = append(s1, s2…)

2.除了在切片的尾部追加,我们还可以在切片的开头添加元素

20.以下代码输出什么?为什么?

package main
import "fmt"
func GetValue(m map[int]string, id int) (string, bool) {
if _, exist := m[id]; exist {
return "存在数据", true
}
return "", false
}
func main() {
intmap := map[int]string{
1: "a",
2: "bb",
3: "ccc",
}
v, err := GetValue(intmap, 3)
fmt.Println(v, err)
}

存在数据 true

考点:map的key是否存在

21.以下代码输出什么?为什么?

package main
func DeferFunc1(i int) (t int) {
t = i
defer func() {
t += 3
}()
return t
}
func DeferFunc2(i int) int {
t := i
defer func() {
t += 3
}()
return t
}
func DeferFunc3(i int) (t int) {
defer func() {
t += i
}()
return 2
}
func main() {
println(DeferFunc1(1))
println(DeferFunc2(1))
println(DeferFunc3(1))
}

更多相关技术资讯内容欢迎前往六星社区了解。

如果你想用Python开辟副业赚钱,但不熟悉爬虫与反爬虫技术,没有接单途径,也缺乏兼职经验
关注下方微信公众号:Python编程学习圈,获取价值999元全套Python入门到进阶的学习资料以及教程,还有Python技术交流群一起交流学习哦。

attachments-2022-06-XsVfzpCF62abf0b801350.jpeg

  • 发表于 2021-05-07 10:49
  • 阅读 ( 508 )
  • 分类:Golang

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
轩辕小不懂
轩辕小不懂

2403 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1474 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章