本文主要介绍GO必知的常见面试问题总结。
目录
什么是引入值类型和引用类型值类型?参考文献的类型有哪些?值类型和引用类型有什么区别?垃圾收集优于千字堆和栈堆切片比较。深层复制和浅层复制操作对象比较的详细说明如下:new和makenew特性,例如:使用技巧。makemake函数的函数签名特征。使用技巧总结:new和make的区别。go的地图实现排序解决方案idea代码实现:运行结果转义分析。最后,听我说。
引言
今年互联网的就业环境真的不好。很多朋友都做了优化。
平时工作中,除了好好编码,贯穿项目,还要内外兼修。你得练好自己的内功和招式,才能应对突发的变故,顺利拿到新的offer。别问我怎么知道的。
这个月我会整理和分享一系列后端工程师面试相关的文章。知识脉络图如下:
JAVA/GO/PHP面试中常见的知识点DB:MySQL PGSQL Cache:Redis Memcache MongoDB数据结构算法微服务高并发流媒体WEB3.0源代码分析
通过这一系列的文章,我们不仅可以对后端开发相关的知识点进行回顾和梳理,还可以知道当前的市场环境对服务器端开发,尤其是对Go开发工程师来说,需要哪些核心技术。
值类型和引用类型
值类型有哪些?基本数据类型都是值类型,包括:int系列、float系列、bool、string、array、struct。
引用类型有哪些?指针、切片、接口接口、管道通道
值类型和引用类型的区别?值类型将值本身存储在内存中,而引用类型将值的内存地址存储在内存中。值类型的内存通常分配在栈中,引用类型的内存通常分配在堆中。
垃圾回收类型的引用内存在堆中分配。当堆中没有变量引用内存地址时,内存地址对应的数据存储空间就变成了垃圾,会被GO语言的GC回收。
一图胜千言堆和栈
栈在Go中,堆栈的内存由编译器自动分配和释放。堆栈区域通常存储函数参数、局部变量和调用函数框架,它们是在函数创建时分配的,但在函数退出时被销毁。
一个goroutine对应一个stack,是call stack的缩写。一个堆栈通常包含许多堆栈框架,这些框架描述了函数之间的调用关系。每一帧对应一个未返回的函数调用,它也以堆栈的形式存储数据。
堆与堆栈不同,应用程序运行时只有一个堆。狭义地说,内存管理只针对堆内存。程序运行过程中,可以主动从堆中申请内存,由Go的内存分配器分配,垃圾收集器收集。
切片
比较切片不能互相比较。我们不能使用==运算符来确定两个切片是否包含所有相等的元素。
切片唯一合法的比较操作是与nil进行比较。
比较的详解
若要检查切片是否为空,您应该使用
透镜==0
来判断,而不应该使用
s==零
来判断。
原因是nil值的切片没有底部数组,nil值的切片长度和容量都是0。但我们不能说一个长度和容量都为0的切片就一定为零。
通过下面的例子我们有了很好的理解:
var S1[]int//len(S1)=0;cap(S1)=0;s1==零
S2:=[]int { }//len(S2)=0;cap(S2)=0;s2!=零
s3 :=make([]int,0)//len(S3)=0;cap(S3)=0;s3!=零
所以判断一个切片是否为空,如果用len(s)==0来判断,就不应该用s==nil来判断。
根本原因是后两种初始化方法已经给切片分配了空间,所以即使切片是空的,也不等于零。但是len(s)==0成立,则切片必须为空。
注意:在go中,var是一个声明关键字,不会打开内存空间;只有当:=或make关键字用于初始化时,内存空间才会打开。
深拷贝和浅拷贝
操作对象深度复制和浅复制操作的对象是Go语言中的引用类型。
区别如下:引用类型的特点是在内存中存储其他值的内存地址;而值类型将实值存储在内存中。
在go语言中,我们用:=赋值来指代浅拷贝的类型,即内存地址被拷贝,两个变量对应同一个内存地址对应同一个值。
a :=[]string{1,2,3}
乙:=甲
如果我们通过copy()函数赋值,就是深度拷贝,赋值的是实值而不是内存地址,会在内存中打开一个新的内存空间。
例子如下:
a :=[]string{1,2,3}
b :=make([]string,len(a),cap(a))
副本(b,a)
new和make
new是NewGo语言的内置函数,其函数签名如下:
func new(Type) *Type
特点
Type表示类型,新函数只接受一个参数,是type *Type表示类型指针,新函数返回指向该类型内存地址的指针。
新功能不常用。类型的指针是使用new函数获得的,指针对应的值是该类型的零值。
举个例子:
func main() {
a :=new(int)
b :=新(布尔值)
fmt。Printf(%Tn ,a) //*int
fmt。Printf(%Tn ,b) //*bool
fmt。Println(*a) //0
fmt。Println(*b) //false
}
使用技巧
Var * int只是声明了一个指针变量A,但是没有初始化。作为一个引用类型,指针在拥有内存空间之前需要初始化,然后才能赋值。
应该使用内置的新函数对进行初始化,如下所示,然后可以对其进行正常赋值:
func main() {
变量a *int
a=新的(整数)
*a=10
fmt。Println(*a)
}
makeMake也用于内存分配,和new不一样。只用于slice、map、channel的内存创建,返回的类型是这三个类型本身,而不是它们的指针类型。因为这三种类型都是引用类型(指针类型),所以不需要返回它们的指针。
make函数的函数签名
func make(t型,尺寸.IntegerType)类型
特点make函数是不可替代的。我们在使用切片、贴图、通道的时候,都需要用make进行初始化,然后才能操作。
使用技巧Var map [string] int这段代码只声明了变量b是一个map类型的变量,它需要像下面的示例代码一样用make函数进行初始化,然后才能被赋予一个键值对:
func main() {
var b map[string]int
b=make(map[string]int,10)
B[分数]=100
fmt。印刷线路(b)
}
小结:new与make的区别两者都用于内存分配。Make只用于切片、贴图、通道的初始化,返回类型本身(类型本身是引用类型(指针类型));new用于内存分配时,对应类型的零值(如0,false)存储在内存中,返回该类型的指针类型。
go的map实现排序
我们知道go语言中map类型的底层是通过hash实现的,hash是乱序的,不支持排序。
如果我们的数据是以map类型存储的,那么如何对其进行排序呢?
解决思路对地图的键进行排序,然后根据排序后的键遍历输出地图。
代码实现:主包装
导入(
fmt
数学/兰特
排序
时间
)
func main() {
Rand.seed (time.now()。UnixNano())//初始化随机数种子
var score map=make(map[string]int,30)
对于I:=0;i lt30;我{
Key:=fmt.sprintf (stud ,I)//生成以stu开头的字符串
值:=兰特。Intn(30) //生成一个从0到50的随机整数
scoreMap[key]=值
}
//取出map中的所有键,并存储在切片键中
var keys=make([]string,0,30)
对于关键字:=范围评分图{
keys=append(keys,key)
}
//对切片进行排序
排序。字符串(键)
//根据排序的键遍历地图
for _,key :=范围键{
fmt。Println(key,scoreMap[key])
}
}
运行结果逃逸分析
逃遁的分析比较辛苦,我单独写了一篇:#【疯狂刷面试题】详细去逃遁分析。
最后,听我说
不要奇怪我为什么要发表这一系列的文章。是的,我最近失业了,所以掘金也失业很久了。我正在努力争取一份新的工作,但是我花了两个星期才得到它。
我想真诚地劝告我所有的朋友:如果你对你的工作不满意,请三思而后行,尤其不要以裸辞为荣。
如果你的公司或者你的部门发展良好,请加倍珍惜这份工作,踏踏实实,为公司做贡献,把不断学习的口号变成落地输出的行动,真正做到用肉眼提升。
如果你和我一样不幸被离开,请不要沮丧,不要抱怨。快速调整自己的负面情绪,进一步提升自己才是王道。
祸从口出:祸从口出,福从口出。
暂时的挫折在人生的长河中不算什么。我们应该做的是尽快收拾行囊,走向下一个更好的前方。尽管道路会崎岖不平,但我们一定会继续前进。
以上是GO必知的常见面试问题汇总的详细内容。更多关于GO面试问题的信息,请关注我们的其他相关文章!