Go基础
文章目录
- Go基础
- ● Go有那些关键字?
- ● Go方法与函数的区别?
- ● Go函数返回局部变量的指针是否安全?
- ● Go函数参数传递是值传递还是引用传递?
- ● defer关键字的实现原理?
- ● 内置函数make和new的区别?
- ● for range 的时候它的地址会发生变化吗?
- ● 简单说一下defer的底层实现原理?defer recover的问题?
- ● uint类型溢出?
- ● 介绍rune类型
- ● golang中解析tag是怎么实现的?反射原理是什么?
- ● 调用函数传入结构体时,应该传值还是指针?
- ● Slice遇到过什么坑?
- ● 两个切片要如何比较?
- ● Go闭包是什么?
- ● 深拷贝和浅拷贝?
- ● init函数的执行时机?
- ● Go 语言中的数组?
欢迎大家观看,如果遇到不合适的答案可以打在评论区,我们一起探讨。
● Go有那些关键字?
package、import、func、return、defer、var、const、interface、struct、chan、map、type、break、case、continue、for、fallthrough、else、if、switch、goto、default、range、go、select。
● Go方法与函数的区别?
函数是指不属于任何结构体的方法。但方法是属于某个结构体的。
● Go函数返回局部变量的指针是否安全?
是安全的。 Go编译器将会对每个局部变量进行逃逸分析。如果发现有局部变量的作用域超出该函数,则不会将内存分配在栈上,而是在堆上,因为他们不在栈区,即使释放函数,其内容也不会受影响。
● Go函数参数传递是值传递还是引用传递?
值传递。 Go中都是值传递,没有引用传递。 如果参数是引用类型,可以修改原内容数据,否则不可以。
● defer关键字的实现原理?
defer可以推迟当前函数返回前才实际执行。 defer和recover结合,形成了Go语言风格的异常与捕获机制。
● 内置函数make和new的区别?
1、作用变量类型不同,new可以对任何类型使用,make只能对切片、字典、通道使用。 2、返回类型不一样,new返回指针,make返回变量本身。 3、new分配的空间被清零,make分配的会初始化。
● for range 的时候它的地址会发生变化吗?
不会。在for range循环中,循环变量的地址在每次迭代时是复用的,直接传递循环变量的地址可能导致所有协程共享同一个地址,出现数据竞争和不期望的行为。
● 简单说一下defer的底层实现原理?defer recover的问题?
先进后出,类似于栈。defer延迟函数,释放资源,收尾工作;如释放锁,关闭文件,关闭链接;捕获panic; 每个 defer 语句都对应一个_defer 实例,多个实例使用指针连接起来形成一个单链表,保存在 gotoutine 数据结构中,每次插入_defer 实例,均插入到链表的头部,函数结束再一次从头部取出,从而形成后进先出的效果。 recover结合defer可以捕获异常,从而防止程序崩溃。recover只有在defer函数中有效。
● uint类型溢出?
无符号整型。2^32-1,如果超出了所能表示的范围,就会发生溢出。溢出不会引发错误或panic,而是导致结果按照模运算。
● 介绍rune类型
相当int32。 golang中的字符串底层实现是通过byte数组的,中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-8。byte 等同于int8,常用来处理ascii字符rune 等同于int32,常用来处理unicode或utf-8字符
● golang中解析tag是怎么实现的?反射原理是什么?
Go 中解析的 tag 是通过反射实现的,反射是指计算机程序在运行时可以访问、检测和修改它本身状态或行为的一种能力或动态知道给定数据对象的类型和结构,并有机会修改它。反射将接口变量转换成反射对象 Type 和 Value;反射可以通过反射对象 Value 还原成原先的接口变量;反射可以用来修改一个变量的值,前提是这个值可以被修改;tag是啥:结构体支持标记,name string json:name-field 就是 json:name-field 这部分
● 调用函数传入结构体时,应该传值还是指针?
传值时,函数会获得给结构体的一个副本,对该副本修改不会影响原来的结构体。 传指针时,引用类型,对指针指向的结构体进行任何的修改都会修改原来的结构体。
● Slice遇到过什么坑?
1、切片容量 切片容量自动增长,当容量不足时,Go会分配一个新的底层数组,并将旧的数组的内容复制到新的数组中。如果频繁增加元素可能导致意外。 应对策略:预先分配足够的容量。 2、切片是对底层数组的引用,多个切片可以共享同一个底层数组。修改一个切片的元素可能会影响其他共享同一底层数组的切片。 如果需要独立的副本,可以使用copy函数创建一个新的切片。 3、切片越界。 4、切片的零值是nil。
● 两个切片要如何比较?
切片不能使用==进行比较,要使用reflect.DeepEqual()进行比较。
● Go闭包是什么?
闭包就是一个可以引用自身作用域之外的变量的函数。即使外部函数完成执行并且作用域被破坏,依然可以访问。
● 深拷贝和浅拷贝?
切片、字典、通道都是引用拷贝,也就是浅拷贝。其余的都是值拷贝,也就是深拷贝。 深拷贝拷贝的是数据本身,创造一个新的对象,并在内存中开辟一个新的内存地址,与原对象是完全独立的,不共享内存,修改新对象时不会影响原对象的值。释放内存时,也没有任何关联。 浅拷贝拷贝的是数据地址,只复制指向的对象的指针,新旧对象的内存地址是一样的,修改一个另一个也会变。释放内存时,同时释放。
● init函数的执行时机?
一个包下可以有多个 init 函数,每个文件也可以有多个 init 函数。多个 init 函数按照它们的文件名顺序逐个初始化。应用初始化时初始化工作的顺序是,从被导入的最深层包开始进行初始化,层层递出最后到 main 包。不管包被导入多少次,包内的 init 函数只会执行一次。应用初始化时初始化工作的顺序是,从被导入的最深层包开始进行初始化,层层递出最后到 main 包。但包级别变量的初始化先于包内 init 函数的执行。
● Go 语言中的数组?
数组是存放元素的容器,Go 语言中数组的长度是数组类型的一部分,定义数组时必须指定存放元素的类型和容量