Golang基础常识性知识面试中常见的六大陷阱及应对技巧

news2024/11/13 9:00:56

一、nil slice & empty slice

1、nil切片与空切片底层

  • nil切片:var nilSlice [] string

    • nil slice的长度len和容量cap都是0

    • nil slice==nil

    • nil slice的pointer是nil

  • 空切片:emptySlice0 := make([]int,0)

    • empty slice的长度是0,容量是由指向底层数组决定

    • empty slice != nil

    • empty slice的pointer是底层数组的地址

  • nil切片和空切片最大的区别在指向的数组引用地址是不一样的

  • nil空切片引用数组指针地址为0(无指向任何实际地址)

图片

  • 空切片的引用数组指针地址是有的,且固定为一个值,所有的空切片指向的数组引用地址都是一样的

图片

2、创建nil slice 和empty slice

package mainimport "fmt"
func main() {  var nilSlice []string  // 创建一个 nil 切片  emptySlice0 := make([]int, 0)  // 方法1:创建一个空切片(零切片)  var emptySlice1 = []string{}   // 方法2:创建一个空切片
  fmt.Printf("\nnilSlice---> Nil:%v Len:%d Capacity:%d", nilSlice == nil, len(nilSlice), cap(nilSlice))  fmt.Printf("\nemptySlice0---> nil:%v Len:%d Capacity:%d", emptySlice0 == nil, len(emptySlice0), cap(emptySlice0))  fmt.Printf("\nemptySlice1---> nil:%v Len:%d Capacity:%d", emptySlice1 == nil, len(emptySlice1), cap(emptySlice1))
  // nil切片和空切片都可以正常 append数据  nilSlice = append(nilSlice, "sss")}/*Nil:true Len:0 Capacity:0nil:false Len:0 Capacity:0nil:false Len:0 Capacity:0[sss] */

二、类型强转产生内存拷贝

1、字符串转数组发送内存拷贝

  • 字符串转成byte数组,会发生内存拷贝吗?

  • 字符串转出切片,会产生拷贝

  • 严格来说,只要是发送类型强转都会发送内存拷贝

  • 那么问题来了,频繁的内存拷贝操作听起来对性能不大友好

  • 有没有什么办法可以在字符串转出切片的时候不用发生拷贝呢?

2、字符串转数组不内存拷贝方法

  • 那么如果想要在底层转换二者,只需要吧StringHeader的地址强转成SliceHeader就行,那么go有个很强的包叫unsafe

  • 1.unsafe.Pointer(&a)方法可以得到变量a的地址。

    • 2.(*reflect.StringHeader)(unsafe.Pointer(&a)) 可以把字符串a转成底层结构的形式。

    • 3.(*[]byte)(unsafe.Pointer(&ssh)) 可以把ssh底层结构体转成byte的切片的指针。

    • 4.再通过 *转为指针指向的实际内容。

package main
import (   "fmt"   "reflect"   "unsafe")
func main() {   a :="aaa"   ssh := *(*reflect.StringHeader)(unsafe.Pointer(&a))   b := *(*[]byte)(unsafe.Pointer(&ssh))   fmt.Printf("%v---%T",b,b)  // [97 97 97]---[]uint8}

三、拷贝大切片一定代价大吗?

  • SliceHeader 是切片在go的底层结构。

    • 第一个字是指向切片底层数组的指针,这是切片的存储空间

    • 第二个字段是切片的长度

    • 第三个字段是容量

type SliceHeader struct {  Data uintptr  Len  int  Cap  int}
  • 大切片跟小切片的区别无非就是 Len 和 Cap的值比小切片的这两个值大一些,如果发生拷贝,本质上就是拷贝上面的三个字段。

  • 所以 拷贝大切片跟小切片的代价应该是一样的

四、map不初始化使用会怎么样

  • 空map和nil map结果是一样的,都为map[]。

  • 所以,这个时候别断定map是空还是nil,而应该通过map == nil来判断。

package main
func main() {  var m1 map[string]string    // 创建一个 nil map  println("m1为nil: ", m1==nil)  // 报错 => panic: assignment to entry in nil map  //m1["name"] = "tom"
  var m2 =  make(map[string]string)  // 创建一个空map  m2["name"] = "jack"                // 空map可以正常  println("m2为nil: ", m2==nil)}

五、map会遍历删除安全吗?

  • map 并不是一个线程安全的数据结构。

  • 同时读写一个 map 是未定义的行为,如果被检测到,会直接 panic。

  • 上面说的是发生在多个协程同时读写同一个 map 的情况下。

  • 如果在同一个协程内边遍历边删除,并不会检测到同时读写,理论上是可以这样做的。

  • sync.Map可以解决多线程读写map问题

    • 一般而言,这可以通过读写锁来解决:sync.RWMutex

    • 读之前调用 RLock() 函数,读完之后调用 RUnlock() 函数解锁;

    • 写之前调用 Lock() 函数,写完之后,调用 Unlock() 解锁。

    • 另外,sync.Map 是线程安全的 map,也可以使用

六、for循环append坑

1、坑1:添加元素变覆盖

  • 不会死循环,for range其实是golang语法糖,在循环开始前会获取切片的长度 len(切片),然后再执行len(切片)次数的循环。

package mainimport "fmt"func main() {  s := []int{1,2,3,4,5}  for _, v:=range s {    s =append(s, v)    fmt.Printf("len(s)=%v\n",len(s))  }}/*len(s)=6len(s)=7len(s)=8len(s)=9len(s)=10 */

2、坑2:值全部一样

  • 每次循转中num的值是正常的,但是由append构造的res中,全是nums的最后一个值。

  • 最终总结出原因是在for range语句中,创建了变量num且只被创建了一次。

  • 即num有自己的空间内存且地址在for循环过程中不变

  • 循环过程中每次将nums中对应的值和num进行值传递

package mainimport "fmt"func main() {  var nums = []int{1, 2, 3, 4, 5}  var res []*int  for _, num := range nums {    res = append(res, &num)    //fmt.Println("num:", num)  }  for _, r := range res {    fmt.Println("res:", *r)  }}/*res: 5res: 5res: 5res: 5res: 5 */

3、解决方法

  • 方法1

    • 不使用for range的形式,直接用索引来对nums取值

package mainimport "fmt"func main() {  var nums = []int{1, 2, 3, 4, 5}  var res []*int  for i := 0; i < len(nums); i++ {    res = append(res, &nums[i])  }  fmt.Println("res:", res)  for _, r := range res {    fmt.Println("res:", *r)  }}
  • 方法2

    • 在for循环中每次再定义一个新的变量num_temp,将num的值传给num_temp,之后append该变量即可。

package mainimport "fmt"func main() {  var nums = []int{1, 2, 3, 4, 5}  var res []*int  for _, num := range nums {    numTemp := num // 创建一个新的临时变量    res = append(res, &numTemp)  }  for _, r := range res {    fmt.Println("res:", *r)  }}/*res: 1res: 2res: 3res: 4res: 5 */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1963085.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法初学者学二分查找

力扣704&#xff0c;二分查找 题目是这样的 二分查找的思路就是&#xff1a; 先确定左右两个边界&#xff0c;左边界是从左往右&#xff0c;右边界是从右往左&#xff0c;所以&#xff0c;左边界是找的比target大的第一个值&#xff0c;右边界最后停的点是比target小的第一个…

谢希仁计算机网络第八版期末复习简答(1)

绪论 计算机网络的概念以及常见的网络类型? 计算机网络&#xff0c;是指地理位置分散的、具有独立功能的多台计算机及其外部设备&#xff0c;通过各种通信线路互联起来&#xff0c;在网络操作系统、网络管理软件及网络通信协议的管理和协调下&#xff0c;实现资源共享和信息…

2024年的AI人工智能风口是Python?一篇文章告诉你为什么!

Python是一种面向对象的、解释型的、通用的、开源的脚本编程语言&#xff0c;它之所以非常流行&#xff0c;我认为主要有三点原因&#xff1a; 1.Python 简单易用&#xff0c;学习成本低&#xff0c;看起来非常干净&#xff1b; 2.Python 标准库和第三库众多&#xff0c;功能…

短剧系统源码分享,快速搭建部署上线教程

一、短剧系统是什么&#xff1f; 短剧制作平台&#xff0c;作为一站式综合解决方案&#xff0c;集剧本创作、角色设计、场景搭建、视频编辑、便捷发布及深度数据分析能力于一身。该平台精准定位于助力企业利用短剧形式强化品牌传播力并驱动商业价值增长&#xff0c;无论企业是…

物理学中三个令人兴奋的想法:稳态作用原理、洛伦兹变换和度量张量

​ 图片来源&#xff1a; https 文章目录 ​一、说明二、最小行动原则三、洛伦兹变换四、Minkowski 公制五、度量张量&#xff1a;曲面的几何形状六、三维欧几里得距离。 ​一、说明 虽然物理学引起了公众的好奇心&#xff0c;但许多人发现数学令人生畏。然而&#xff0c;物理…

C#知识|文件与目录操作:目录的操作

哈喽,你好啊,我是雷工! 前边学习了文件的删除、复制、移动,接下来学习目录的操作。 以下为学习笔记。 01 效果演示 1.1、显示指定目录下的所有文件 在左侧的文本框中显示出F:\F004-C#目录下的所有文件, 演示效果: 1.2、显示指定目录下的所有子文件 在左侧的文本框中显…

Serverless Knative冷启动与自动扩缩容研究:从原理到实践

最近一个研究生网页的提问&#xff0c;然后就有了这篇博客&#xff01; 大佬你好&#xff0c;我看到您的关于Serverless的文章于是十分冒昧的向您提问。我现在是一名在研究通过Serverless容器调度解决冷启动问题的本科生&#xff0c;导师放养&#xff0c;就让看论文但是后面的代…

多态、接口、类练习题

代码&#xff1a; public static void main(String[] args) {Person2 personnew Person2("唐僧",new Horse());person.passRiver();person.onRoad();} 接口&#xff1a; interface Vehicles{public void work(); } lass Horse implements Vehicles{Overridepubli…

HIS系统开发,医院HIS系统开发注意事项

在当今信息化迅速发展的时代&#xff0c;医院信息系统&#xff08;HIS&#xff09;的开发已成为提升医疗服务效率和质量的关键。HIS系统的开发并非易事&#xff0c;它涉及到众多复杂的技术和管理问题。以下是开发HIS系统时需要特别注意的几个关键问题。 数据安全与隐私保护是HI…

正点原子imx6ull-mini-Linux驱动之Linux 并发与竞争实验(8)

在上一章中我们学习了 Linux 下的并发与竞争&#xff0c;并且学习了四种常用的处理并发和竞争的 机制&#xff1a;原子操作、自旋锁、信号量和互斥体。本章我们就通过四个实验来学习如何在驱动中使 用这四种机制。 1&#xff1a;原子操作实验 本例程我们在第四十五章的 gpiol…

不想交智商税的都收藏了!K9、希喂、渴望,最近风超大的猫咪主食罐测评

宠物行业有多卷咱就不说了&#xff0c;反正某宝一打开品牌多达上百个&#xff0c;各种猫粮产品更是数不胜数&#xff01;不懂点门道的人选起来确实有点费脑子。不过我养猫这七八年来&#xff0c;前前后后入手过的主食罐头少说也有三十来款&#xff0c;自认还是积累了一些经验。…

《python语言程序设计》2018版第6章第21题平方根的近似求法math模块里有几种实现sqrt函数的方法

只能针对“1111” 或者“77”这样的&#xff0c;其它的不行。但是很成功了 def sqrt(n):lastGuess 0#我让他们两个相等&#xff0c;来建立循环的条件nextGuess n#这样就给了lastGuess和nextGuess进行循环的条件while lastGuess ! nextGuess:lastGuess 1nextGuess (lastGue…

【宝藏系列】物联网中常用的十种通信协议

【宝藏系列】物联网中常用的十种通信协议 文章目录 【宝藏系列】物联网中常用的十种通信协议1️⃣MQTT2️⃣CoAP3️⃣AMQP4️⃣XMPP5️⃣LwM2M6️⃣HTTP7️⃣DDS8️⃣Bluetooth Low Energy9️⃣LoRaWAN1️⃣0️⃣NB-IoT 1️⃣MQTT MQTT&#xff08;Message Queuing Telemetry T…

51单片机和STM32区别

51单片机和 STM32 区别 51单片机和 STM32 是两种常见的微控制器&#xff0c;它们在架构、性能、外设接口、功耗和开发环境等方面有所不同。 1. 架构差异 51单片机基于传统的哈佛总线结构&#xff0c;采用 CISC 架构&#xff0c;而 STM32 基于 ARM Cortex-M 系列的32位处理器核…

JavaScript高级程序设计教程(第3版 电子版教程)

前言 JavaScript 是一种非常松散的面向对象语言&#xff0c;也是 Web 开发中极受欢迎的一门语言。JavaScript&#xff0c;尽管它的语法和编程风格与 Java 都很相似&#xff0c;但它却不是 Java 的“轻量级”版本&#xff0c;甚至与 Java 没有任何关系。JavaScript 是一种全新的…

vue一些npm i 时报错问题解决【JAVA前后端分离】

前端vue npm i 安装时出现 作为一个懂些前端得 JAVA开发自然是要粗暴解决这个问题了 问题解决 使用命令 npx -p npm6 npm i 即可编译 原因&#xff1a; ERESOLVE与npm版本有关&#xff0c;因为npm版本高对某些事情比npm6.x更严格。通常&#xff0c;最简单的解决方法是将--…

农合生活平台更新升级啦!了解详情戳这里

7月24日&#xff0c;农合生活平台完成了新一轮的版本更新。新版本上线后&#xff0c;农元NYT购买数量将不做限制&#xff0c;优惠券更易得&#xff0c;购物更划算&#xff0c;农元价值升值将进一步「加速度」。 更新说明 1. 数量&#xff1a;旧版本中农元只能定额定量购买&…

卡奥斯智能交互引擎:引领工业智能,共创数字化未来

​智能交互引擎&#xff1a;https://www.cosmoplat.cnhttps://datayi.cn/w/nPN4v4e9 &#x1f4d6;一、平台简介 卡奥斯智能交互引擎聚焦工业领域,是卡奥斯结合海尔40年的工业制造经验积累和7年工业互联网平台建设的最佳工业智能实践。该引擎集成了工业大模型技术,基于卡奥斯…