golang面试题(带答案)

这篇博客主要探讨了Go语言中的一些核心概念和特性,包括变量引用、并发、通道、defer、panic与recover、类型定义以及错误处理等。通过一系列的面试题目,深入解析了Go语言的值传递、切片、映射、通道的使用细节,特别是并发编程中的select和goroutine的运行机制。此外,还讨论了类型定义、常量声明、变量简短模式以及通道在并发控制中的应用。
摘要由CSDN通过智能技术生成

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)

	}

}

                
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值