GO必知必会面试题汇总

简介: GO必知必会面试题汇总

值类型和引用类型


值类型有哪些?


基本数据类型都是值类型,包括:int系列、float系列、bool、字符串、数组、结构体struct。


引用类型有哪些?


指针、切片slice、接口interface、管道channel


值类型和引用类型的区别?


  1. 值类型在内存中存储的是值本身,而引用类型在内存中存储的是值的内存地址。
  2. 值类型内存通常在栈中分配,引用类型内存通常在堆中分配。


垃圾回收


引用类型的内存在堆中分配,当没有任何变量引用堆中的内存地址时,该内存地址对应的数据存储空间就变成了垃圾,就会被GO语言的GC回收。


一图胜千言


微信图片_20221113150950.jpg


微信图片_20221113151000.jpg


堆和栈



在Go中,栈的内存是由编译器自动进行分配和释放,栈区往往存储着函数参数、局部变量和调用函数帧,它们随着函数的创建而分配,函数的退出而销毁。

一个goroutine对应一个栈,栈是调用栈(call stack)的简称。一个栈通常又包含了许多栈帧(stack frame),它描述的是函数之间的调用关系,每一帧对应一次尚未返回的函数调用,它本身也是以栈形式存放数据。



与栈不同的是,应用程序在运行时只会存在一个堆。狭隘地说,内存管理只是针对堆内存而言的。程序在运行期间可以主动从堆上申请内存,这些内存通过Go的内存分配器分配,并由垃圾收集器回收。


切片


比较


切片之间是不能比较的,我们不能使用==操作符来判断两个切片是否含有全部相等元素。

切片唯一合法的比较操作是和nil比较。


比较的详解


要检查切片是否为空,应该使用


len(s) == 0


来判断,而不应该使用


s == nil


来判断。


原因是:一个nil值的切片并没有底层数组,一个nil值的切片的长度和容量都是0。但是我们不能说一个长度和容量都是0的切片一定是nil。


我们通过下面的示例就很好理解了:


var s1 []int            //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{}           //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0)    //len(s3)=0;cap(s3)=0;s3!=nil


所以要判断一个切片是否是空的,要是用len(s) == 0来判断,不应该使用s == nil来判断。

其根本原因在于后面两种初始化方式已经给切片分配了空间,所以就算切片为空,也不等于nil。但是len(s) == 0成立,则切片一定为空。


注意:在go中 var是声明关键字,不会开辟内存空间;使用 := 或者 make 关键字进行初始化时才会开辟内存空间。


深拷贝和浅拷贝


操作对象


深拷贝和浅拷贝操作的对象都是Go语言中的引用类型


区别如下:


引用类型的特点是在内存中存储的是其他值的内存地址;而值类型在内存中存储的是真实的值。

我们在go语言中通过 := 赋值引用类型就是 浅拷贝,即拷贝的是内存地址,两个变量对应的是同一个内存地址对应的同一个值。


a := []string{1,2,3} 
b := a


如果我们通过copy()函数进行赋值,就是深拷贝,赋值的是真实的值,而非内存地址,会在内存中开启新的内存空间。

举例如下:


a := []string{1,2,3} 
b := make([]string,len(a),cap(a)) 
copy(b,a)


new和make


new


new是GO语言一个内置的函数,它的函数签名如下:


func new(Type) *Type


特点


  • Type表示类型,new函数只接受一个参数,这个参数是一个类型
  • *Type表示类型指针,new函数返回一个指向该类型内存地址的指针。


new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。


举个例子:


func main() {
    a := new(int) 
    b := new(bool)
    fmt.Printf("%T\n", a) // *int 
    fmt.Printf("%T\n", b) // *bool 
    fmt.Println(*a) // 0 
    fmt.Println(*b) // false 
}


使用技巧


var a *int只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。

应该按照如下方式使用内置的new函数对a进行初始化之后就可以正常对其赋值了:


func main() {
    var a *int
    a = new(int)
    *a = 10
    fmt.Println(*a)
}


make


make也是用于内存分配的,区别于new,它只用于slice、map以及channel的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型(指针类型),所以就没有必要返回他们的指针了。


make函数的函数签名


func make(t Type, size ...IntegerType) Type


特点


make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。


使用技巧


var b map[string]int这段代码,只是声明变量b是一个map类型的变量,需要像下面的示例代码一样使用make函数进行初始化操作之后,才能对其进行键值对赋值:


func main() { 
    var b map[string]int 
    b = make(map[string]int, 10) 
    b["分数"] = 100 
    fmt.Println(b)
}


总结:new与make的区别


  1. 二者都是用来做内存分配的。
  2. make只用于slice、map以及channel的初始化,返回的是类型本身(类型本身就是引用类型(指针类型));
  3. 而new用于内存分配时,在内存中存储的是对应类型的型零值(比如0,false),返回的是该类型的指针类型。


Go的map如何实现排序


我们知道Go语言的map类型底层是由hash实现的,是无序的,不支持排序。

如果我们的数据使用map类型存储,如何实现排序呢?


解决思路


排序map的key,再根据排序后的key遍历输出map即可。


代码实现:


package main
import (
   "fmt"
   "math/rand"
   "sort"
   "time"
)
func main() {
   rand.Seed(time.Now().UnixNano()) //初始化随机数种子
   var scoreMap = make(map[string]int, 30)
   for i := 0; i < 30; i++ {
      key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
      value := rand.Intn(30)           //生成0~50的随机整数
      scoreMap[key] = value
   }
   //取出map中的所有key存入切片keys
   var keys = make([]string, 0, 30)
   for key := range scoreMap {
      keys = append(keys, key)
   }
   //对切片进行排序
   sort.Strings(keys)
   //按照排序后的key遍历map
   for _, key := range keys {
      fmt.Println(key, scoreMap[key])
   }
}


运行结果


微信图片_20221113151003.jpg


搞定,非常顺滑!


公众号:程序员升级打怪之旅

微信号:wangzhongyang1993

相关文章
|
1月前
|
缓存 前端开发 中间件
[go 面试] 前端请求到后端API的中间件流程解析
[go 面试] 前端请求到后端API的中间件流程解析
|
1月前
|
算法 Go
[go 面试] 雪花算法与分布式ID生成
[go 面试] 雪花算法与分布式ID生成
|
1月前
|
Go 调度 开发者
[go 面试] 深入理解进程、线程和协程的概念及区别
[go 面试] 深入理解进程、线程和协程的概念及区别
|
1月前
|
并行计算 数据挖掘 大数据
[go 面试] 并行与并发的区别及应用场景解析
[go 面试] 并行与并发的区别及应用场景解析
|
9天前
|
算法 程序员 Go
PHP 程序员学会了 Go 语言就能唬住面试官吗?
【9月更文挑战第8天】学会Go语言可提升PHP程序员的面试印象,但不足以 solely “唬住” 面试官。学习新语言能展现学习能力、拓宽技术视野,并增加就业机会。然而,实际项目经验、深入理解语言特性和综合能力更为关键。全面展示这些方面才能真正提升面试成功率。
33 10
|
1月前
|
存储 负载均衡 算法
[go 面试] 一致性哈希:数据分片与负载均衡的黄金法则
[go 面试] 一致性哈希:数据分片与负载均衡的黄金法则
|
1月前
|
运维 监控 容灾
[go 面试] 实现服务高可用的策略和实践
[go 面试] 实现服务高可用的策略和实践
|
1月前
|
Go API 数据库
[go 面试] 分布式事务框架选择与实践
[go 面试] 分布式事务框架选择与实践
|
1月前
|
安全 Go 调度
[go 面试] 深入理解并发控制:掌握锁的精髓
[go 面试] 深入理解并发控制:掌握锁的精髓
|
1月前
|
SQL 安全 测试技术
[go 面试] 接口测试的方法与技巧
[go 面试] 接口测试的方法与技巧