当前位置:首页 > 科技  > 软件

Go 面试中的隐藏陷阱:SliceHeader 问题解析

来源: 责编: 时间:2024-06-12 17:31:35 282观看
导读大家好,我是煎鱼。最近也是面试季+毕业季了,很多同学正在积极准备面试。尤其是很多同学,已经通过官网资料熟悉了 Go 基本语法,但没有太大把握。希望对一些常见的棘手面试问题做一些预习。今天和大家学习 @Harutyun Mardir

大家好,我是煎鱼。3FG28资讯网——每日最新资讯28at.com

最近也是面试季+毕业季了,很多同学正在积极准备面试。尤其是很多同学,已经通过官网资料熟悉了 Go 基本语法,但没有太大把握。希望对一些常见的棘手面试问题做一些预习。3FG28资讯网——每日最新资讯28at.com

今天和大家学习 @Harutyun Mardirossian 大佬分享的面试题,一起进步!3FG28资讯网——每日最新资讯28at.com

面试问题

请先在脑子里思考一下具体的运行结果,再查看答案。3FG28资讯网——每日最新资讯28at.com

如下代码:3FG28资讯网——每日最新资讯28at.com

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

面试问题:fmt.Println 的输出结果是什么?3FG28资讯网——每日最新资讯28at.com

问题解析

运行程序,查看输出结果:3FG28资讯网——每日最新资讯28at.com

[]

fmt.Println 最终打印的是一个长度为 0 的切片。3FG28资讯网——每日最新资讯28at.com

答案是:空切片。(你答对了吗?)3FG28资讯网——每日最新资讯28at.com

在 Go 中,函数参数是按值传递的,这意味着上述代码在参数传递时,创建了参数值的副本并传递给函数。3FG28资讯网——每日最新资讯28at.com

而切片实际上是一个包含长度(len)、容量(cap)和指向底层数组指针(data)的结构体。3FG28资讯网——每日最新资讯28at.com

当我们将切片作为函数参数传递时,实质上复制的是切片的 SliceHeader,对应的底层数组是保持不变的。3FG28资讯网——每日最新资讯28at.com

结合代码来讲,就是因为在 doSomething 函数中,创建了 SliceHeader 的新副本。然后 append 函数会在超过容量时重新分配新切片,并返回更新后的切片。3FG28资讯网——每日最新资讯28at.com

深入验证

我们可以使用 unsafe 包去打印 SliceHeader(切片头),进行进一步的验证和分析。3FG28资讯网——每日最新资讯28at.com

如下代码:3FG28资讯网——每日最新资讯28at.com

type SliceHeader struct {    Data uintptr    Len  int    Cap  int}func main() {    s := make([]int, 0, 2)    sh := (*SliceHeader)(unsafe.Pointer(&s))    fmt.Println(sh)    doSomething(s)}func doSomething(a []int) {    a = append(a, 1)    sh := (*SliceHeader)(unsafe.Pointer(&a))    fmt.Println(sh)}

输出结果:3FG28资讯网——每日最新资讯28at.com

&{1374389592336 0 2} // main&{1374389592336 1 2} // doSomething

两个切片的 Data 指针地址指向的是同一个底层数组。但由于长度不同,它们在应用的表现上是两个不同的切片。3FG28资讯网——每日最新资讯28at.com

这也印证了前面问题的结果是输出了空切片,切片长度为 0 的内部原理。3FG28资讯网——每日最新资讯28at.com

变通方法

这种情况下,建议是修改写法,提高代码易读性。否则后续维护也比较麻烦,不熟悉的同学咋一眼一看很有可能发现不了问题。3FG28资讯网——每日最新资讯28at.com

但如果你还是希望输出你想要的切片值,可以采取以下变通方法。3FG28资讯网——每日最新资讯28at.com

改动后的代码:3FG28资讯网——每日最新资讯28at.com

func main() {    s := make([]int, 0, 2)    doSomething(s)    fmt.Println(s[:1]) // 进行新的切片操作}func doSomething(a []int) {    a = append(a, 1)}

输出结果:3FG28资讯网——每日最新资讯28at.com

[1]

原因是在进行 s[:1] 切片操作时,本质上是创建了一个新的 SliceHeader,所以可以正常打印和获取预期的元素。3FG28资讯网——每日最新资讯28at.com

当然,还有一种常见的写法就是切片 append 等变更后一定做一遍再赋值,这样可以规避掉不少使用上的细节坑。3FG28资讯网——每日最新资讯28at.com

总结

今天这篇文章讨论了一个很常见的 Go 面试问题,内容涉及切片作为函数参数的传递和修改。3FG28资讯网——每日最新资讯28at.com

重点在于切片作为参数是按值传递的,因此函数内部的修改不会影响外部变量。3FG28资讯网——每日最新资讯28at.com

如果仍然希望获取可以通过切片操作,重新切分一下新的切片结果集就可以了。3FG28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-93368-0.htmlGo 面试中的隐藏陷阱:SliceHeader 问题解析

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: C#托管堆遭破坏问题溯源分析

下一篇: 基于 Spring Boot 与 WebSocket 实现实时车位管理与状态更新

标签:
  • 热门焦点
  • 7月安卓手机性能榜:红魔8S Pro再夺榜首

    7月份的手机市场风平浪静,除了红魔和努比亚带来了两款搭载骁龙8Gen2领先版处理器的新机之外,别的也想不到有什么新品了,这也正常,通常6月7月都是手机厂商修整的时间,进入8月份之
  • 十个可以手动编写的 JavaScript 数组 API

    JavaScript 中有很多API,使用得当,会很方便,省力不少。 你知道它的原理吗? 今天这篇文章,我们将对它们进行一次小总结。现在开始吧。1.forEach()forEach()用于遍历数组接收一参
  • 得物效率前端微应用推进过程与思考

    一、背景效率工程随着业务的发展,组织规模的扩大,越来越多的企业开始意识到协作效率对于企业团队的重要性,甚至是决定其在某个行业竞争中突围的关键,是企业长久生存的根本。得物
  • Flowable工作流引擎的科普与实践

    一.引言当我们在日常工作和业务中需要进行各种审批流程时,可能会面临一系列技术和业务上的挑战。手动处理这些审批流程可能会导致开发成本的增加以及业务复杂度的上升。在这
  • JavaScript学习 -AES加密算法

    引言在当今数字化时代,前端应用程序扮演着重要角色,用户的敏感数据经常在前端进行加密和解密操作。然而,这样的操作在网络传输和存储中可能会受到恶意攻击的威胁。为了确保数据
  • 共享单车的故事讲到哪了?

    来源丨海克财经与共享充电宝相差不多,共享单车已很久没有被国内热点新闻关照到了。除了一再涨价和用户直呼用不起了。近日多家媒体再发报道称,成都、天津、郑州等地多个共享单
  • 梁柱接棒两年,腾讯音乐闯出新路子

    文丨田静 出品丨牛刀财经(niudaocaijing)7月5日,企鹅FM发布官方公告称由于业务调整,将于9月6日正式停止运营,这意味着腾讯音乐长音频业务走向消亡。腾讯在长音频领域还在摸索。为
  • 品牌洞察丨服务本地,美团直播成效几何?

    来源:17PR7月11日,美团App首页推荐位出现“美团直播”的固定入口。在直播聚合页面,外卖“神枪手”直播间、美团旅行直播间、美团买菜直播间等均已上线,同时
  • 英特尔Xe HPG游戏显卡:拥有512EU,单风扇版本

    据10 月 30 日外媒 TheVerge 消息报道,英特尔 Xe HPG Arc Alchemist 的正面实被曝光,不仅拥有 512 EU 版显卡,还拥有 128EU 的单风扇版本。另外,这款显卡 PCB
Top