正文部分转载自知乎 -- 张小方 -- 在“高粱GOLANG”写的文章
原文链接:写给想去字节写 Go 的你 - 高梁Golang教程网 (kandaoni.com)
小白可以看看前言,有一定借鉴意义
目录
前言
Go入门
正文
一、为什么字节跳动选择使用 Go 语言?
例子一
例子二
性能与效率上的对比
语法层面上的对比
1. 每一行语句的结尾不再强行要求加上分号
2. 一对大括号的第一个不能单独占一行
3. if/for 等语句体只有一行时也必须使用一对大括号包裹起来
4. if/for 等条件不再需要括号
5. 只有 for 循环,不再支持 while 和 do - while 循环
6. switch - case 语句默认加了 break 语句
7. 自增自减运算符只支持后缀形式,不支持前缀形式
8. 不支持条件运算符(? :)
9. 给一个结构体多个字段设置值时,最后一个字段也必须以逗号结束
功能完备性的对比
结论
二、求职字节 Go 开发岗位需要如何准备?
2、尽量写上一门自己擅长的语言即可
3、校招看基础,社招看经验
4、字节很注重算法能力
5、字节很注重动手能力
6、网上的面经适当看,带着理解与批判精神去看
7、C++ 和 Java 太难了,直接学 Go 吧
事项
2023/7/20拿到了字节青训营的入营通知,24号要开入营班会,考虑到暑假时间不足,所以考虑后续再跟进学习和项目,不是为了学Go这门语言,而是为了掌握背后的通用知识和技巧
--------当然,如果以后有机会拿到字节的实习,就更好了,拿不到就老老实实继续打基础,或者争取点中小厂的暑期 or 日常实习
青训营录取
选定C++了,要学的很多,不要急,打基础阶段很重要,面试考察更多的也是基础,多点耐心。。。现在连入门都不算,来日方长,养足精神,保证身体健康,才有能力应对未来的挑战
暑期任务情况
截止2023 / 7 / 20,暑期过半,说实话,有点压力
(完不成是板上钉钉的,只希望能完成80%)
以至于晚上睡不着,爬起来玩3小时游戏,再敲1.5小时代码,又是一个通宵
暂定打算
(1)再花2天时间,跟完C++视频
(2)然后开始专攻Mysql视频和《算法训练营》
(3)同时抽3~5天搞定1~2个Github开源,有完善文档,代码能跑通的小小小项目(大概200~1000行之间,但是,国外大佬写的项目,即使只有200行,难度也是有的,你会接触到很多没见过的库,插件和语法,,当然,还有十分陌生,或者说相对规范的编码风格)
(4)当C++和Mysql视频都跟完后,花上2周把2本书刷掉
--> 《Essential C++》和《Mysql必知必会》--> 记住!是速刷,不要再慢慢看了
(5)至此,暑期任务的核心部分完成了,然后就是佛系看Acw辅导课的视频
(6)还有Java一周速刷掉一套10小时左右的视频
(7)研究研究Go的相关文档和青训营的学习资源
(8)内蒙呼伦贝尔必须跑一趟,补足点精神养分,在家里躺了2个月会废掉的,虽然说有运动
目前困境
(1)
一周总有2~3天摆烂,不太愿意学习,更愿意组团玩游戏,整天基本上只能认真学1个小时
作息也变成了昼伏夜出,总是22:00起床,洗澡1小时,锻炼1小时,放松0.5小时,吃饭1小时,游戏1小时,然后开始学习.....下步刚买了新的泳裤泳帽和眼镜,除了健身和足球,会增加游泳,当你要出门见人,你就不会整晚通宵.....希望有用
(2)
效率有待提升,总喜欢事无巨细地跟着把代码敲下来,写成博客,一有一点点困惑就问G平pt,借鉴stackoverflow的建议
翻译:“你有时间问弱智Gpt,不如自己去查官方文档”,比如之前跟Github源码,遇到
error: swprintf_s was not declared in this scope的BUG,第一时间问Gpt,结果gpt也不懂,乱说一通,然后Google,没有类似问题,百度也没用....最后stackoverflow被拒才发现问题的根源,太过依赖gpt,其实gpt只能作为新手入门使用,或者前端方面稍强,后端或者算法题真的很差劲。
(目前发现个比较大的问题就是,没有养成查阅官方文档的习惯,当然,你也可以通过编译器右键选项查看源码,更重要的是阅读文档的一点英文能力和习惯)
正确做法:第一时间到cppreference检索swprintf_s,woc,一检索,2分钟找到问题....所以,多点接触这些信息,不要闭门造车,被骂两句总好过困死在自己的信息茧房里
【置顶】Go语言学习之路/Go语言教程 | 李文周的博客 (liwenzhou.com)
从 Java 的角度初识 Go 语言 | 青训营笔记 - HikariLan's Blog (minecraft.kim)
一文学会 Go 的三个主流开发框架| 青训营笔记 - HikariLan's Blog (minecraft.kim)
Hertz | CloudWeGo
hertz/README_cn.md at develop · cloudwego/hertz (github.com)
先做下自我介绍,目前人在字节做后端开发,工作语言主要是 Go,字节万千面试官之一,出版图书《C++ 服务器开发精髓》一书。在来字节使用 Go 之前,我写了多年 C/C++ 和 Java。
如果你想来字节工作或者想与我交流一些职业问题,可以戳下面的卡片:
确实如题主所说,字节后端服务大多使用 Go。那为什么字节跳动选择使用 Go 语言呢?
目前后端服务能胜任大型项目的编程语言有 C/C++、Java 和 Go,在给出答案之前,我们先看几个编程语言之间对比的例子。
有下面一段 Go 代码:
C/C++ 转 Go 语言的同学刚开始看到这样的代码可以正常运行是不敢相信的,在早些年的计算机的编程语言入门课中,老师和无数课本一直告诫我们:不要返回一个局部变量(栈变量)的地址,因为在函数调用结束后,栈被销毁,引用已经销毁的栈中的变量可能会出现内存问题。然而,这样的代码在 Go 中工作的很好,也很常用。
然而 Java 开发的同学就很习惯这样的代码,因为在 Java 中随处可见这样的代码,但是,Java 中创建 myItem 这样的对象毕竟使用的是堆内存呀。如果熟悉 Java 虚拟机回收内存的常见方法,对 Go 语言中这种用法也会了然于心。Go 开发者之所以可以这样写代码,是因为 Go 编译器替我们做了额外的内存分配和回收工作。从这个意义上来讲,C++ 也可以使用堆内存实现同样的功能,代码如下:
在 C++ 中需要开发者自己记得在必要的时候释放 myItem 占用的内存,当然,从 C++ 的角度来说,这样的做法是一种不好的实践:C++ 最佳实践建议内存是谁分配的就由谁来释放。在这个函数中分配内存,在另外一个函数中释放内存,一般不推荐这么做。
前段时间有位同学来面试,我看这位同学简历上写了熟悉 C++ 和 Go,我就问这位同学觉得 Go 语言中有哪些好用的特性,该同学提到了 defer 关键字,于是我们就 Go 中的 defer 关键字讨论了一下,我的问题是:用 C++ 可以实现 defer 关键字的等价功能吗?
以下是该同学的回答:
结论是可以的,因为 Go 中 defer 关键字是在当前函数执行完毕(或者说是出了当前函数作用域)时,自动执行一些我们指定的动作,一般用于资源的回收。代码如下:
上述 Go 代码中,由于使用了 defer 语句,无论哪一步的 myFile.Read 函数操作失败了,最终文件都会被关闭,避免了文件句柄的泄漏。
在 C++ 中我们可以使用 RAII 技术实现同样的效果,只要构造一个 RAII 类即可,即在类的析构函数关闭文件,这样这个文件一旦打开,只要出了函数作用域都会被关闭。代码如下:
上述 C++ 代码中利用了 RAII 技术达到了和 Go defer 关键字一样的效果,这位面试的同学表达的就是这个意思。
当然,这位同学回答的并不完整,Go 的 defer 关键字所能达到的一些作用,C++ 中没有与之等价的功能。
在 C++ 中,虽然在大多数情况下可以使用 RAII 技术达到在出了函数作用域时执行我们指定的动作,但是有一种情况 defer 关键字可以做到,C++ RAII 却做不到,那就是当函数执行过程中有崩溃问题(Go 中叫 panic)时,可以在 defer 指定的动作中恢复程序的执行流,不让整个进程退出,而 C++ 程序是无法做到针对一个内存问题造成的 crash 恢复进程继续执行的。Go 代码如下:
上述 Go 代码中,由于 RecoverFromCrash 函数操作了一个空指针,导致程序崩溃,然后 defer 配合 recover 函数可以恢复程序继续运行。也就是说,如果采用这种机制,一个 goroutine 产生的崩溃不会影响到其他 goroutine。这在 C++ 中是绝对无法做到的,在 C++ 程序中,任何内存问题都会导致整个进程退出。这外在表现就是,使用 Go 开发出来的程序,一个接口有问题不会影响到同一个服务中不相关的接口,更不会导致整个服务宕机,这是 C++ 程序绝对无法做到的。
除此以外, defer 关键字还做了更多工作,defer 关键字在程序崩溃时可以恢复部分数据,这点很有用,我们可以基于此记录一些程序崩溃时的现场值,这在 C++ 中根本做不到这一点。代码如下:
C++ 开发者无数次幻想过有一种方法可以在进程内恢复因内存问题而崩溃的进程,更不用说记录进程崩溃时的现场数据了,而这在 Go 中均做到了,而且如此简单易用。C++ 开发者看到这里眼泪要流下来了。
作为面试官,该面试者能想到 C++ RAII 技术可以等价部分 Go 的 defer 关键字功能,我已经很满意了,倘若能更进一步,就很完美了。
对于 Java 来说,我们可以使用 try -catch - finally 关键字实现 defer 的上述功能,只要将代码如下:
虽然在 Java 中可以把 Go 中 defer 需要做的事情放到 finally 部分,但是实际业务中导致程序出现异常有很多原因,为了避免进程不因为未处理的异常而退出,我们必须捕获顶级 Exception,在 Java 中这是一种不推荐的方式。
好了,说完这两个例子之后,让我们来对比一下 Go 与 C/C++/Java 的优缺点。
C++ 最让人诟病的问题是需要开发者自己管理内存,从学习这块知识的角度来看,编码中直接管理内存是管理不好的,开发者必须学习与内存相关的各种操作系统原理,最起码要知道物理内存与虚拟内存、栈内存与堆内存、内存分配与释放时机、进程地址空间的内存分布、各个内存地址区间的内存读写属性、如何避免内存越界等等相关知识,而这些知识不是一蹴而就就能学会的,所以如果某个开发者能写出一个经年累月不需要重启或者不宕机的 C++ 服务,那他是个高手。但是在快速迭代业务的互联网公司,怎么可能人人都是高手呢?万一某天来了个新人加了一个新功能,导致一个隐蔽的内存问题,之后就是恼人的问题排查与定位。
C++ 自己管理内存是把双刃剑,高手可以用来写出高效的程序来,但是对于新手或者水平不够的开发者来说,这将是企业产品事故甚至灾难的源泉。
再者,拜当下各种焦虑的、浅尝辄止的、急功近利的网文的宣传,无论是个人还是公司,已经没有多少人愿意把时间花在学习周期长、难度大的 C++ 语言之上了。只要在满足业务要求的情况下,公司当然愿意花更低的成本去使用更能保证业务快速、稳定迭代的 Go 语言上了。
那么 Java 呢?Java 最大的问题是,其编译出来的程序不是操作系统原生支持的可执行文件,必须运行在 Java 虚拟机之中,这样要想运行必须依赖于 Java 虚拟机,而对于复杂业务来说,生成的 Jar 文件也偏臃肿。所以无论是安装 Java 程序的本身需要的运行环境还是生成的 Jar 文件的执行效率大大折扣。
我列一张表来对比一下 C++、Java 与 Go 在性能与可执行文件体积上的差别,需要说明一下,这张表是针对具有复杂功能的中大型项目来说的:
工作的早些年,我在使用 C/C++ 和 Java 进行编程时,曾思考这样一个问题,既然大多数的代码行末尾必须都要以分号结束,那为啥编译器不直接代劳此事?从编译原理的角度来说,大多数代码行末尾的分号都是没有任何作用的。
而更早的学生时代,我常常因为忘记在某些代码行的结尾写上分号而导致代码无法编译通过,我相信,在今天,数以万计的刚开始接触编程的同学也遇到和我曾经一样的问题。
另外一个情形就是很多同学在写 switch - case 语句的时候,有时候因为忘记在特定的 case 语句之后写上 break 语句,从而导致程序执行时出现非预期的行为,这个问题也同样困扰着学习编程的新人们。
一对大括号中的第一个大括号是否要单独放在一行;if/for 等执行体只有一条语句时,是否应该使用一对大括号包裹起来,这类问题在开发者之间争论了几十年,并且将继续在后来者那里争论下去,就算是像《代码大全》这样经典的书籍也花了好几页去讨论这两种代码风格哪种好,更不用说各个公司为了统一编码风格而制定的各种代码规范和 lint 检查规则了。
继往开来,Go 语言大刀阔斧地去除了一些其他语言中看起来不是很必要的功能,这些功能的去除让 Go 的风格变得统一、简洁,在 Go 项目中,大家不会再为上文中提到的几个风格问题而争论了。
让我们来看一下 Go 语言相对于其他语言所做的一些改动,欢迎读者在评论区补充:
如果你真的想执行完一个 case 接着执行下一个 case,只要使用 fallthrough 关键字就可以了:
以上列举了 Go 精简后的一些语法要素,精简后的语法,让编程初学者更容易记忆与上手。
极少的语法元素,让 Go 简单易学,字节的大多数同学都是入职后两周内学习的 Go,然后开始着手业务开发。
Go 与 Java 相比较于 C++,其语言自带的 API 库功能是相当完善的,从基本的字符串操作到网络编程、文件读写等等应用尽有,因此 Go 的开发者可使用的原生 API 就很丰富,比如编写一个网络通信程序,Go 和 Java 都在 net 包中提供了大量可使用的 API,而 C++ 必须直接借助操作系统的 Socket API。
这就是我说的语言的功能完备性,如果一个编程语言自带的 API 越丰富,那么开发者只要尽可能地掌握语言自身的 API 就可以了,自身的 API 通常会屏蔽了各个操作系统的差异性,学习成本更低,同样是 Socket API,学习 Go 或者 Java SDK 自带的网络 API,要比直接学习多个操作系统的 Socket API 要容易得多。
对于 C++ 语言来说,随着 C++ 标准的不断发展,C++ 语言自身的功能完备性也在逐步完善,例如从 C++11 开始,就可以直接使用 stl 中的线程相关的类,而不用再使用操作系统提供的线程接口。
综上所述,我给出我的结论,正因为 Go 语言简单易学、不容易出错、功能完备性良好且执行效率高,特别适合字节这样有超多超快的业务线产品迭代。当然,Go 语言想入门容易,想学好成为高手并不容易,很多从其他语言转到 Go 开发的同学,若不刻意勤加练习,想写出地道、高效的 Go-Style 风格的代码也不是一件很容易的事情。
这里推荐几本我学习 Go 的书籍:
网上有人分享出来(建议购买正版票):
链接: https://pan.baidu.com/s/1ZGSV05sQ3JkaPwzON26Jhw 密码: tqk1
相比较为什么字节跳动选择使用 Go 语言,很多同学可能更关心求职字节跳动 Go 开发岗位要如何准备。
如果你也想来字节写 Go,我可以帮你内推(也可以提供简历修改建议),当然内推非开发岗也是可以的,内推请戳下面这个链接:
有读者看到这篇文章私信我,问了类似这样的问题,自己是其他语言(C/C++/Java/Python),没有 Go 基础能否投递字节的 Go 岗位,我这里想说的是,据我所知,字节的 Go 岗位一般对 Go 本身没有多少要求,如果你不熟悉 Go,基本上面试不会问 Go 的任何问题。而是安排相应的面试官问你之前的语言相关的,最重要的是,对于校招和工作年限不长的社招一般算法和数据结构是硬性要求。
也就是说,你可以不熟悉 Go 语言也可以应聘字节的 Go 开发岗位,但是有几个注意事项:
1、虽然不要求熟悉 Go 开发,但要求熟悉至少一门编程语言
字节很多进来做 Go 的同学之前都是做 C、C++ 或者 Java, 甚至是 php 或者 Python 的。所以,如果你之前根本没接触过 Go 或者接触过但不熟悉 Go,尽量不要在简历中写自己熟悉 Go。这样面试的时候面试官也就不会考察你任何关于 Go 本身的问题,这点很重要,比如,你原来是做 C++ 或者 Java 的,你为了应聘这个岗位强行写上自己熟悉 Go,那么面试官可能会重点考察一下你的 Go 技术栈,这样你相当于被考察一个不熟悉的技术栈,你很吃亏。我曾内推的几位同事,包括最近面试的一两位同学都是这样,拿自己弱项来接受考察,面试结果一般都不尽人意。以上文中那位同学为例,如果他不在简历中写自己熟悉 C++ 和 Go,只写自己熟悉 C++,我就不会问他任何关于 Go 的问题了,比如 defer 关键字的问题。
这里的意思是,如果你之前是做 C++ 开发的,那你就写上你熟悉 C++,Java 也一样,这样面试的时候,除了通用部分,面试官会考察你相应的语言相关的内容,例如简历上写了熟悉 C++,如果连 C++ 虚函数的实现机制、stl 常用容器都说不清楚,那明显不符合预期;写熟悉 Java 的,HashMap、Java 的线程池 ThreadPoolExecutor、Java 虚拟机等都是常考的内容。我看过一部分同学未通过面试的原因是:不管熟悉不熟悉的技术栈都一股脑儿地写到简历中,结果面试时被问到又说不清楚。
基础知识就那么多,包括算法与数据结构、操作系统原理、计算机网络(网络编程)、多线程、数据库、设计模式等等;社招看经验,所谓经验,不仅指良好的基本功,还包括丰富的项目经验和解决问题的能力,一般 2-1 及以上职级的基本上要求至少擅长分布式、RPC、消息中间件、缓存、数据库等至少其中的一种。另外,就是解决问题的能力,很多算法题或者场景题都是源自于真实的业务场景,需要面试者给出自己解决问题的思路和可以落地的方法。
通常情况下, 对于校招生,算法题做不好,基本一票否决;对于社招,工作五年及五年以下的,也会考察一部分算法题。很多工作多年的同学,由于平时不注重温习和理解算法与数据结构知识,忘记了很多算法思想和解决问题的策略。给这部分同学的建议是:
除了一些算法岗位,社招的算法题一般都不难,有些算法题也不单纯是考察算法,可能结合其他知识点一起考察,这里列举一些题目给读者做一些参考:
如果你对这些算法题有不明白的地方,可以通过我的公众号加我的微信群交流。
上述题目部分是《剑指 offer》一书的原题,我向读者推荐一下这本书,另外一本是左程云老师的《程序员代码面试指南》。
网上也有人将这两本书分享出来(建议购买正版哦):
链接: https://pan.baidu.com/s/1q-tHJ-lr3ShL4TjSlPu75Q 密码: 4wnh
适当刷一些算法题,不单纯为了应付面试,对锻炼思维能力也是大有裨益的。
而且对于校招,通常这块答的不好,基本就被一票否决了。这也是我建议那些参加校招的同学要好好准备算法和数据结构的题目了。 说到这里,为一些学历不错但是因为在校招前不认真准备这块、最终无缘字节的同学感到惋惜,懒惰两个月,影响职业生涯一辈子。
我分享一下我的算法题库 + 整理了一些常见的大厂算法题与面经:
通常算法这块的题目并不难,但是一定要在面试前好好准备一下。
当然,很多非科班的同学一上来就刷算法题,其实是不推荐的,如果你没有系统地学习过算法和数据结构的课程,建议先系统地学习下这一块的内容。
疫情仍然没有完全过去,现在字节的面试基本上都是改在线上进行,当面试官给你一些算法题或者场景题时,需要你在自己的电脑上进行编程,在编程过程中的各种行为,例如你的编写代码、解决编译错误、调试能力和代码风格都是面试官一眼能看到的。平常动手多寡、高下立判,我曾遇到用 VSCode 写 Java 代码然后连编译问题都解决不了的同学,显然,最终面试肯定也未通过。
面试大厂的结果有一定的运气成分,不同的人在不同的场景面试遇到不同的面试官其表现的面试结果可能也不一样。
近来我发现有些校招的同学,把网络上的面经和所谓的标准答案一字不拉地背诵下来用于应付面试,这是非常不可取的:
其一,有些面筋的答案本身就是错的,例如网上有一篇流传很广的文章,谈到 HTTP GET 与 POST 请求的区别时,说 GET 请求会发送一个数据包,而 POST 请求则会拆成两个数据包去发送,这种说法明显就是错误的。很多同学不加甄别的背诵下来,我迄今至少遇到两位同学面试时这么回答;
其二,光背面经如果不加以理解很难应付灵活变化的面试题,例如,有些同学把三四握手和四次挥手的过程背诵下来了,但是当我问到连接一个 IP 不存在的主机时,握手过程是怎样的、或者连接一个 IP 地址存在但端口号不存在的主机握手过程又是怎样的呢?如果对三次握手过程不加以理解,是很难回答出这样的问题的。企业需要一些理解技术原理并能灵活运用的员工,而不是死记硬背的人。
很多同学觉得 C++ 太难了,学不好,Java 学的人太多,竞争压力大,所以干脆学 Go 吧,上文说过,各大招 Go 岗位的公司其实对 Go 本身不做刻意要求,反而对技术原理要求不低。所以,打铁还得自身硬,想靠学 Go 走捷径其实行不通,技术基本功决定着你将来在技术这条路上能走多远。那些看似难啃的技术原理,今天所欠下的技术债,总会在你的职业生涯的某一个阶段爆发出来。以学习 C/C++ 为例,如果你学习 C/C++ 单纯只是为了找工作或者应付面试,那一定也是学不好的,C++ 语法本身并没有多难,难的是支持 C++ 技术背后的各种操作系统原理,这些原理你在 C/C++ 中会用到,你在学习其他语言到一定阶段也不可或缺;反过来,以网络编程为例,在 Go 中讨论 epoll 模型多少有点别捏,或者是说不清道不明,但是站在 C/C++ 的角度结合操作系统的网络 API,这个问题就很容易搞明白了。
所以,对于开发这条路来说,换一门容易学的语言并不能让你拥有核心竞争力。相反,如果你想做好开发,尤其是后端开发,你应该掌握一门重型编程语言,如 C++ 或者 Java,这也是为什么我劝那些想做好开发的同学不要只掌握一门 Python/PHP 这样的语言。
限于笔者经验水平有限,欢迎在文末温和地提出建议和意见。
推荐阅读
很多同学私信我想了解下我的技术成长经历,这里分享一下我的学习书单吧(少即是精):