最全Golang面试题——基础知识_golang基础试题(3),Golang插件化主流框架和实现原理

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

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

// 输出
4
1
3


  DeferFunc1中,有名返回(指定返回值命名func test() (t int)),执行 return 语句时,并不会再创建临时变量保存,defer 语句修改了t,即对返回值产生了影响,所以返回4。


  DeferFunc2中,无名返回(返回值没有指定命名),执行Return语句后,Go会创建一个临时变量保存返回值,defer 语句修改的是 t,而不是临时变量,所以返回1。


  DeferFunc3中,有名返回,执行 return 语句时,把2赋值给t,defer 语句再执行t+1,所以返回3。


### 2、for range


  range 循环会复用地址,&stu实际上一致指向同一个指针,最终该指针的值为遍历的最后一个struct的值拷贝。(for循环复用局部变量i)



func main() {
m := make(map[string]*student)
stus := []student{
{Name: “zhou”, Age: 24},
{Name: “li”, Age: 23},
{Name: “wang”, Age: 22},
}
// 错误写法
for _, stu := range stus {
fmt.Printf(“%p\n”, &stu)
m[stu.Name] = &stu
}
for k, v := range m {
fmt.Println(k, “=>”, v.Name)
}

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

}

// 输出
0xc000008078
0xc000008078
0xc000008078
zhou => wang
li => wang
wang => wang
zhou => zhou
li => li
wang => wang


**for 和 for range有什么区别?**


* 使用场景不同  
   for可以遍历array和slice、遍历key为整型递增的map、遍历string  
   for range可以完成所有for可以做的事情,却能做到for不能做的,包括遍历key为string类型的map并同时获取key和value、遍历channel。
* 实现不同  
   for可以获取到的是被循环对象的元素本身,可以对其进行修改;  
   for range使用值拷贝的方式代替被遍历的元素本身,是一个值拷贝,而不是元素本身。



func main() {
five := []string{“Annie”, “Betty”, “Charley”, “Doug”, “Edward”}

for \_, v := range five {
	five = five[:2]
	fmt.Printf("v[%s]\n", v)
}
fmt.Println(five)

}
//v[Annie]
//v[Betty]
//v[Charley]
//v[Doug]
//v[Edward]
//[Annie Betty]
//循环内的切片值会缩减为2,但循环将在切片值的自身副本上进行操作。这允许循环使用原始长度进行迭代而没有任何问题,因为后备数组仍然是完整的。


### 3、go的并发


  i++不是原子操作,会出现并发问题。Go 提供了一个检测并发访问共享资源是否有问题的工具, race 参数:go run -race main.go


  第一个go协程中i是外部for的一个变量,地址不变化,每次指向的都是一样的地址,遍历完成后,最终i=10。


  第二个go协程中i是函数参数,会发生值拷贝,地址会变,内部每次指向新的地址。



func main() {
var wg sync.WaitGroup
wg.Add(10)

// 错误
for i := 0; i < 10; i++ {
	go func() {
		fmt.Println(i)
		wg.Done()
	}()
}

// 正确
for i := 0; i < 10; i++ {
	go func(i int) {
		fmt.Println(i)
		wg.Done()
	}(i)
}
wg.Wait()

}


### 4、select随机性


  select会随机选择一个可用通道做收发操作。 所以代码是有肯触发异常,也有可能不会。select可以在多个chan间等待执行,有三点原则:


* select 中只要有一个case能return,则立刻执行。
* 当如果同一时间有多个case均能return则伪随机方式抽取任意一个执行。
* 如果没有一个case能return则可以执行”default”块。



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


### 5、make默认值和append


  make初始化是有默认值的,默认值为0。append函数执行完后,返回的是一个全新的 slice,并且对传入的 slice 并不影响。



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

func main() {
s := []int{5}
s = append(s, 7)
s = append(s, 9)
x := append(s, 11)
y := append(s, 12)
fmt.Println(s, x, y)
}
//[5 7 9] [5 7 9 12] [5 7 9 12]


### 6、结构体比较


  结构体是可以比较的,但前提是结构体成员字段全部可以比较,并且结构体成员字段**类型、个数、顺序**也需要相同,当结构体成员全部相等时,两个结构体相等。


  特别注意的点,如果结构体成员字段的顺序不相同,那么结构体也是不可以比较的。如果结构体成员字段中有不可以比较的类型,如map、slice、function 等,那么结构体也是不可以比较的。



func main() {
sn1 := struct {
age int
name string
}{age: 11, name: “Zhang San”}
sn2 := struct {
age int
name string
}{age: 11, name: “Zhang San”}

fmt.Println(sn1 == sn2) // 输出 true


sn3 := struct {
	name string
	age  int
}{age: 11, name: "Zhang San"}

fmt.Println(sn1 == sn3)
// 错误提示:Invalid operation: sn1 == sn3 (mismatched types struct {...} and struct {...})


sn4 := struct {
	name string
	age  int
	grade map[string]int
}{age: 11, name: "Zhang San"}
sn5 := struct {
	name string
	age  int
	grade map[string]int
}{age: 11, name: "Zhang San"}

fmt.Println(sn4 == sn5)
// 错误提示:Invalid operation: sn4 == sn5 (the operator == is not defined on struct {...})

}


### 7、type


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



//错误
func main(key int) {
switch key.(type) {
case int:
println(“int”)
case interface{}:
println(“interface”)
default:
println(“unknown”)
}
}
//正确

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

1715556733000)]
[外链图片转存中…(img-mQ8iugDV-1715556733000)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值