欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang基礎常識性面試中常見的六大陷阱及應對技巧總結

 更新時間:2024年08月06日 09:53:53   作者:少林碼僧  
Go是一門簡單有趣的語言,但與其他語言類似,它會有一些技巧,這篇文章主要給大家介紹了關于Golang基礎常識性面試中常見的六大陷阱及應對技巧的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

一、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切片和空切片最大的區(qū)別在指向的數組引用地址是不一樣的

  • nil空切片引用數組指針地址為0(無指向任何實際地址)

圖片

  • 空切片的引用數組指針地址是有的,且固定為一個值,所有的空切片指向的數組引用地址都是一樣的

圖片

2、創(chuàng)建nil slice 和empty slice

package main
import "fmt"
func main() {
  var nilSlice []string  // 創(chuàng)建一個 nil 切片
  emptySlice0 := make([]int, 0)  // 方法1:創(chuàng)建一個空切片(零切片)
  var emptySlice1 = []string{}   // 方法2:創(chuàng)建一個空切片
  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:0
nil:false Len:0 Capacity:0
nil:false Len:0 Capacity:0[sss]
 */

二、類型強轉產生內存拷貝

1、字符串轉數組發(fā)送內存拷貝

  • 字符串轉成byte數組,會發(fā)生內存拷貝嗎?

  • 字符串轉出切片,會產生拷貝

  • 嚴格來說,只要是發(fā)送類型強轉都會發(fā)送內存拷貝

  • 那么問題來了,頻繁的內存拷貝操作聽起來對性能不大友好

  • 有沒有什么辦法可以在字符串轉出切片的時候不用發(fā)生拷貝呢?

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
}
  • 大切片跟小切片的區(qū)別無非就是 Len 和 Cap的值比小切片的這兩個值大一些,如果發(fā)生拷貝,本質上就是拷貝上面的三個字段。

  • 所以 拷貝大切片跟小切片的代價應該是一樣的

四、map不初始化使用會怎么樣

  • 空map和nil map結果是一樣的,都為map[]。

  • 所以,這個時候別斷定map是空還是nil,而應該通過map == nil來判斷。

package main

func main() {
  var m1 map[string]string    // 創(chuàng)建一個 nil map
  println("m1為nil: ", m1==nil)
  // 報錯 => panic: assignment to entry in nil map
  //m1["name"] = "tom"

  var m2 =  make(map[string]string)  // 創(chuàng)建一個空map
  m2["name"] = "jack"                // 空map可以正常
  println("m2為nil: ", m2==nil)
}

五、map會遍歷刪除安全嗎?

  • map 并不是一個線程安全的數據結構。

  • 同時讀寫一個 map 是未定義的行為,如果被檢測到,會直接 panic。

  • 上面說的是發(fā)生在多個協程同時讀寫同一個 map 的情況下。

  • 如果在同一個協程內邊遍歷邊刪除,并不會檢測到同時讀寫,理論上是可以這樣做的。

  • sync.Map可以解決多線程讀寫map問題

    • 一般而言,這可以通過讀寫鎖來解決:sync.RWMutex。

    • 讀之前調用 RLock() 函數,讀完之后調用 RUnlock() 函數解鎖;

    • 寫之前調用 Lock() 函數,寫完之后,調用 Unlock() 解鎖。

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

六、for循環(huán)append坑

1、坑1:添加元素變覆蓋

  • 不會死循環(huán),for range其實是golang語法糖,在循環(huán)開始前會獲取切片的長度 len(切片),然后再執(zhí)行len(切片)次數的循環(huán)。

package main
import "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)=6
len(s)=7
len(s)=8
len(s)=9
len(s)=10
 */

2、坑2:值全部一樣

  • 每次循轉中num的值是正常的,但是由append構造的res中,全是nums的最后一個值。

  • 最終總結出原因是在for range語句中,創(chuàng)建了變量num且只被創(chuàng)建了一次。

  • 即num有自己的空間內存且地址在for循環(huán)過程中不變

  • 循環(huán)過程中每次將nums中對應的值和num進行值傳遞

package main
import "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: 5
res: 5
res: 5
res: 5
res: 5
 */

3、解決方法

  • 方法1

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

package main
import "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循環(huán)中每次再定義一個新的變量num_temp,將num的值傳給num_temp,之后append該變量即可。

package main
import "fmt"
func main() {
  var nums = []int{1, 2, 3, 4, 5}
  var res []*int
  for _, num := range nums {
    numTemp := num // 創(chuàng)建一個新的臨時變量
    res = append(res, &numTemp)
  }
  for _, r := range res {
    fmt.Println("res:", *r)
  }
}
/*
res: 1
res: 2
res: 3
res: 4
res: 5
 */

總結

到此這篇關于Golang基礎常識性面試中常見的六大陷阱及應對技巧總結的文章就介紹到這了,更多相關Golang面試常見陷阱及應對內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • golang使用sync.singleflight解決熱點緩存穿透問題

    golang使用sync.singleflight解決熱點緩存穿透問題

    在go的sync包中,有一個singleflight包,里面有一個?singleflight.go文件,代碼加注釋,一共200行出頭,通過?singleflight可以很容易實現緩存和去重的效果,避免重復計算,接下來我們就給大家詳細介紹一下sync.singleflight如何解決熱點緩存穿透問題
    2023-07-07
  • golang讀取yaml配置文件的方法實現

    golang讀取yaml配置文件的方法實現

    本文主要介紹了golang讀取yaml配置文件的方法實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-10-10
  • Golang中Set類型的實現方法示例詳解

    Golang中Set類型的實現方法示例詳解

    這篇文章主要給大家介紹了關于Golang中Set類型實現的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-09-09
  • golang雙鏈表的實現代碼示例

    golang雙鏈表的實現代碼示例

    這篇文章主要介紹了golang雙鏈表的實現代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • go語言的四數相加等于指定數算法

    go語言的四數相加等于指定數算法

    這篇文章主要介紹了go語言的四數相加等于指定數算法的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 淺析Go使用定時器時如何避免潛在的內存泄漏陷阱

    淺析Go使用定時器時如何避免潛在的內存泄漏陷阱

    這篇文章來和大家一起探討一下Go?中如何高效使用?timer,特別是與select?一起使用時,如何防止?jié)撛诘膬却嫘孤﹩栴},感興趣的可以了解下
    2024-01-01
  • Go REFLECT Library反射類型詳解

    Go REFLECT Library反射類型詳解

    這篇文章主要為大家介紹了Go REFLECT Library反射類型詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權詳解

    Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權詳解

    最近項目中需要用到鑒權機制,golang中jwt可以用,這篇文章主要給大家介紹了關于Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權的相關資料,需要的朋友可以參考下
    2022-09-09
  • 淺談Golang如何使用Viper進行配置管理

    淺談Golang如何使用Viper進行配置管理

    在Golang生態(tài)中,Viper是一個不錯的開源配置管理框架,這篇文章主要為大家介紹了Golang如何使用Viper進行配置管理,需要的可以參考一下
    2023-06-06
  • Go經典面試題匯總(填空+判斷)

    Go經典面試題匯總(填空+判斷)

    這篇文章主要介紹了Go經典面試題匯總(填空+判斷),本文章內容詳細,具有很好的參考價值,希望對大家有所幫助,需要的朋友可以參考下
    2023-01-01

最新評論