網站首頁 編程語言 正文
引言
今年互聯網的就業環境真的好糟糕啊,好多朋友被優化。
我們平常在工作中除了擼好代碼,跑通項目之外,還要注意內外兼修。內功和招式都得練??,才能應對突如其來的變故,順利的拿到新的offer,不要問我怎么知道的。
這個月我會整理分享一系列后端工程師求職面試相關的文章,知識脈絡圖如下:
- JAVA/GO/PHP 面試常問的知識點
- DB:MySql PgSql
- Cache: Redis MemCache MongoDB
- 數據結構
- 算法
- 微服務&高并發
- 流媒體
- WEB3.0
- 源碼分析
通過這一系列的文章,大家不僅能溫習和梳理后端開發相關的知識點,也可以了解目前的市場環境對服務端開發,尤其是對Go開發工程師的崗位要求,需要掌握哪些核心技術。
值類型和引用類型
值類型有哪些?
基本數據類型都是值類型,包括:int系列、float系列、bool、字符串、數組、結構體struct。
引用類型有哪些?
指針、切片slice、接口interface、管道channel
值類型和引用類型的區別?
- 值類型在內存中存儲的是值本身,而引用類型在內存中存儲的是值的內存地址。
- 值類型內存通常在棧中分配,引用類型內存通常在堆中分配。
垃圾回收
引用類型的內存在堆中分配,當沒有任何變量引用堆中的內存地址時,該內存地址對應的數據存儲空間就變成了垃圾,就會被GO語言的GC回收。
一圖勝千言
堆和棧
棧
在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的區別
- 二者都是用來做內存分配的。
- make只用于slice、map以及channel的初始化,返回的是類型本身(類型本身就是引用類型(指針類型));
- 而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]) } }
運行結果
逃逸分析
逃逸分析比較硬核,單獨寫了一篇文章:# 【狂刷面試題】Go逃逸分析詳解
最后,聽我說
不用好奇我為什么會出這個系列的文章,沒錯,我最近處于失業狀態,所以掘金也斷更了好久,疲于奔命的在為拿到新offer而奮斗,好在花了2周的時間拿到了新的offer。
在此衷心的勸誡各位小伙伴:如果你對你的工作不滿意,請三思再三思之后再離職,尤其不要傲嬌的裸辭。
如果你的公司或者你的部門發展的還不錯,請你加倍珍惜這份工作,踏踏實實,為公司發光發熱,貢獻力量,把不斷學習的口號轉化成落地輸出的行動,真真正正的做到肉眼可見的提高。
如果你也和我一樣不幸被離職,請不要沮喪更不要抱怨,快速調整負面情緒,進一步提升自己才是王道。
福禍相依:禍兮福之所倚,福兮禍之所伏。
暫時的失意放在人生的長河中算不上什么,我們要做的應該是盡快收拾起行囊,朝著下一個更美好的前方走去,哪怕路上會磕磕絆絆,但是我們一定會抬足向前。
原文鏈接:https://juejin.cn/post/7131717990558466062
相關推薦
- 2022-06-30 Python利用shutil模塊實現文件夾的復制刪除與裁剪_python
- 2022-09-22 git commit后,如何撤銷commit
- 2022-06-11 sql?server查詢語句阻塞優化性能_MsSql
- 2022-10-01 SQL中concat和substr組合運用解析_MsSql
- 2023-07-28 ElementUI el-tabs切換之前判斷是否滿足切換條件 不滿足條件僅提示不切換Tab
- 2022-06-25 Python+PuLP實現線性規劃的求解_python
- 2022-03-15 spark-submit hive SQL standards based authorizati
- 2023-01-19 利用Python構建Flutter應用的教程詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支