65道Go基礎高頻題整理(附答案背誦)

說明一下Golang 中 make 和 new 的區別?

好的,關於 makenew 在 Go 語言中的區別,我來解釋一下。

  1. new 函數的作用

    • new(T) 函數會爲 T 類型的新項分配零值內存,並返回其地址,即一個 *T 類型的值(指針)。這種方法適用於各種類型,包括基本類型如 intfloatbool 等,以及數組、結構體等。
    • 使用 new 分配的內存被初始化爲類型的零值,例如 new(int) 返回的指針指向的值會被初始化爲 0。
  2. make 函數的作用

    • make 函數僅用於切片(slice)、映射(map)和通道(channel)的內存分配,並返回一個有初始值(非零值)的 T 類型,而不是 *T
    • 對於切片,make 會分配內存並初始化切片的內部結構,如長度和容量等。
    • 對於映射,make 會初始化映射的結構。
    • 對於通道,make 會配置通道的緩衝大小。
  3. 應用場景與例子

    • 使用 new
      • 當你需要一個指向某基本類型零值的指針時,比如在需要在函數間共享或者更改數據時。
      • 例子:num := new(int) 創建了一個指向整數的指針,其值初始化爲 0。
    • 使用 make
      • 創建切片、映射或通道時,並且需要它們立即可用,例如要在切片中存儲數據,或者在映射中設置鍵值對。
      • 例子:s := make([]int, 10) 創建了一個長度和容量都是 10 的整數切片。

總結:newmake 都是用於分配內存,但 new 返回的是指針,且適用於所有類型,而 make 只用於切片、映射和通道,並返回一個初始化的(非零值的)類型實例。

說明一下 Golang 數組和切片的區別?

Golang 中數組和切片是兩種不同的數據類型,它們有以下幾個主要區別:

  1. 長度固定性

    • 數組:數組的長度是固定的,定義時必須指定長度,並且一旦定義,其長度不能更改。
    • 切片:切片是動態的,長度可以改變。切片實際上是對數組的抽象。
  2. 聲明方式

    • 數組:聲明時需要指定長度,例如 var a [5]int 定義了一個包含 5 個整數的數組。
    • 切片:在聲明切片時,不需要指定長度,例如 var s []int 是一個切片,初始時爲空。
  3. 內部結構

    • 數組:數組直接存儲值,數組的大小和元素類型一起定義了數組的類型。
    • 切片:切片包含三個元素:一個指向底層數組的指針,切片的長度,以及切片的容量。因此,切片比數組更加靈活。
  4. 傳遞方式

    • 數組:在函數調用時,數組是通過值傳遞的,這意味着傳遞的是整個數組的副本。
    • 切片:切片是通過引用傳遞的,所以函數內部對切片的修改會影響到原切片。
  5. 使用場景

    • 數組:當你需要固定長度的序列時使用數組。例如,你知道你只需要存儲 12 個月的名稱,可以使用數組。
    • 切片:更加常用,特別是當你需要一個可伸縮的列表時。例如,你在處理一個用戶列表,這個列表可能會根據用戶註冊的增減而變化。
  6. 性能考慮

    • 數組:由於大小固定,內存分配在棧上,因此訪問速度快。
    • 切片:更加靈活,但需要小心處理容量和長度的變化,可能會涉及到內存重新分配。

總結:數組是靜態的、固定長度的序列,而切片是動態的、可以伸縮的序列。切片在 Go 中更加常用,提供了更高的靈活性和便利性。

使用for range 的時候,它的地址會發生變化嗎?

在 Go 語言中,for range 循環的行爲取決於你正在遍歷的數據類型。對於數組或切片,for range 會提供每個元素的副本,而不是直接引用原始元素。因此,如果你嘗試獲取這些元素的地址,你會發現地址在每次迭代中都會改變,因爲你實際上獲取的是副本的地址。

這點可以通過以下的例子來說明:

nums := []int{10, 20, 30}
for i, v := range nums {
    fmt.Printf("Index: %d, Value: %d, Address: %p\n", i, v, &v)
}

在上述代碼中,v 是數組元素的副本,而不是直接引用。因此,&v 在每次迭代中都會產生不同的地址,這些地址指向的是副本的位置,而不是原始數據的位置。

但是,如果你直接操作原始數組(或切片)的元素,例如:

nums := []int{10, 20, 30}
for i := range nums {
    fmt.Printf("Index: %d, Value: %d, Address: %p\n", i, nums[i], &nums[i])
}

在這個例子中,&nums[i] 將在每次迭代中提供原始元素的地址,這些地址在每次迭代中都是不變的,因爲它們直接引用了原始數據。

總結:在 for range 循環中,如果嘗試獲取每次迭代中提供的元素的地址,這些地址會在每次迭代中改變,因爲這些元素是原始數據的副本。如果你需要操作原始數據的地址,你應該直接引用原始數據。

go defer,多個 defer 的順序,defer 在什麼時機會修改返回值?

defer關鍵字在Go語言中用於確保函數調用在程序執行完畢後,無論函數是否出現錯誤,都能正確地被執行。當有多個defer語句在同一函數中,他們會以LIFO(後進先出)的順序執行。這就意味着在同一個函數內,最後聲明的defer語句會被最先執行。

關於修改返回值,defer語句在函數返回之後執行,但是它可以訪問並修改返回值。這是因爲返回值在函數結束時會被當作defer語句的參數。這意味着如果你在defer函數中修改了返回值,那麼實際的返回值會被改變。

以下是一個簡單的例子來解釋這個概念:

package main

import "fmt"

func main() {
    fmt.Println(deferTest())
}

func deferTest() (result int) {
    defer func() {
        result++
    }()
    return 0
}

在這個例子中,deferTest函數的返回值在沒有defer語句的情況下應該是0。但是,因爲我們在defer語句中將result增加了1,所以最終返回的值實際上是1。當我們運行main函數,輸出結果就是1,而不是0

簡要說明一下Golang 單引號,雙引號,反引號的區別?

在 Go 語言中,單引號 ('), 雙引號 ("), 和反引號 (```) 都被用於表示字符串,但是它們的用途和行爲有所不同:

  1. 單引號 (' ') :用於表示單個字符(rune)。它包含的字符必須是 Unicode 編碼的字符,例如 'a''中' 或者 Unicode 編碼 'u4E2D'。不能用於表示字符串。

    例如:

    var char rune = 'a'
    ```
    
    
  2. 雙引號 (" ") :用於表示字符串。字符串是 UTF-8 字符的序列。字符串內的特殊字符可以通過反斜槓 (\) 進行轉義。

    例如:

    var str string = "Hello, World!\n"
    ```
    
    
  3. 反引號 (` `) :也用於表示字符串,但是反引號表示的字符串會保留原始內容,包括換行和其他特殊字符,不支持任何轉義序列。

    例如:

    var str string = `Hello,
    World!`
    ```
    
    

在這個例子中,反引號字符串會保留原始的換行符。

總結:單引號用於表示字符,雙引號和反引號用於表示字符串,但雙引號支持轉義序列,而反引號保留字符串的原始格式。

Go的函數與方法及方法接受者區別?

在Go語言中,函數和方法都是用來封裝代碼的,但它們在使用方式上有一些不同。

函數是具有一組輸入參數和返回值的獨立實體,它不依賴於任何類型。例如:

func Add(a int, b int) int {
    return a + b
}

在這個例子中,Add是一個函數,它接受兩個整數作爲輸入,然後返回兩個整數的和。

方法是依賴於特定類型的函數,這個特定類型被稱爲方法的接收者。例如:

type MyInt int

func (m MyInt) Add(otherInt int) int {
    return int(m) + otherInt
}

在這個例子中,Add是一個方法,它的接收者是MyInt類型。這意味着我們可以在任何MyInt類型的實例上調用Add方法。

方法接收者可以是任何類型的值或者指針,不過不能是一個接口類型或者一個指針類型。接收者的類型在方法名前,以(接收者) 方法名的形式出現。

方法接收者有兩種類型:值接收者和指針接收者。值接收者方法在調用時,接收者的值會被複制,而指針接收者在調用方法時,會使用接收者的實際地址,所以可以修改接收者的值。

type MyInt int

func (m MyInt) valueReceiver() {    // 值接收者
    m = 5
}

func (m *MyInt) pointerReceiver() { // 指針接收者
    *m = 5
}

func main() {
    var num MyInt = 2
    num.valueReceiver()
    fmt.Println(num)  // 輸出 2
    num.pointerReceiver()
    fmt.Println(num)  // 輸出 5
}

在這個例子中,你會看到valueReceiver方法沒有改變num的值,而pointerReceiver方法改變了num的值。

能詳細介紹一下Golang中的defer底層數據結構和特性嗎?

在 Go 語言中,defer 關鍵字用於推遲一個函數或方法的執行,直到包含該 defer 語句的函數執行完成。這個被延遲的函數被稱爲 "deferred function"。

defer 的主要特性包括:

  1. 後進先出(LIFO):當在一個函數中存在多個 defer 語句時,它們將會以後進先出的順序執行。也就是說,最後一個 defer 語句最先被執行,第一個 defer 語句最後被執行。

  2. 參數在 defer 語句中立即求值:在 defer 語句中,函數的參數會立即被計算並保存,而函數本身的執行會被延遲。

  3. 延遲函數的執行時機defer 的函數會在包含 defer 語句的函數返回之前執行,無論這個函數是通過 return 正常結束,還是由於 panic 導致的異常結束。

關於 defer 的底層實現,Go 運行時使用了一個叫做 "deferred function stack" 的結構來管理 defer 調用。這是一個後進先出(LIFO)的棧結構,每當遇到 defer 調用,運行時就會將其添加到當前 goroutine 的 defer 棧中。每個棧幀包含了被推遲函數的指針以及其參數,這些參數在 defer 語句被執行時就已經被求值。

當包含 defer 語句的函數即將返回時,運行時會從 defer 棧中彈出一個棧幀,並執行其中的函數。如果有多個 defer 語句,那麼就會按照後進先出的順序依次執行。

總之,defer 提供了一種強大的機制,可以用來處理資源的清理工作,如關閉文件句柄、解鎖互斥鎖等,無論函數由於何種原因結束,都能保證資源的正確清理。

能否介紹一下Golang中的slice底層數據結構和特性?

Go語言中的切片(slice)是一種動態數組,它的底層數據結構包括三個關鍵的屬性:指針、長度和容量。

  1. 指針(Pointer):指向數組的第一個元素。
  2. 長度(Length):當前切片的長度,即包含的元素數量。
  3. 容量(Capacity):從切片的開始位置到底層數組的結尾位置的元素數量。

Go語言的切片是引用類型,它們不存儲任何數據,只描述底層數組的一段。更改切片的元素會修改其底層數組中的對應元素。

切片的長度和容量可以通過內置的 len()cap() 函數獲取。您可以通過 append() 函數向切片添加元素。如果添加的元素數量超過切片的容量,append() 會創建一個新的底層數組,並將原始數據複製到新數組中,然後返回新的切片。

這是一個簡單的例子:

package main

import "fmt"

func main() {
    // 創建一個切片
    s := []int{1, 2, 3}
    fmt.Println(len(s), cap(s)) // 輸出:3 3

    // 添加一個元素
    s = append(s, 4)
    fmt.Println(len(s), cap(s)) // 輸出:4 6
}

在這個例子中,我們首先創建了一個包含三個元素的切片。然後,我們向切片添加了一個元素,因爲切片的容量不足以容納新的元素,所以 append() 創建了一個新的底層數組,並將原始切片的數據複製到新數組中,然後返回了新的切片。新切片的容量是原始切片的容量的兩倍。

在Golang中,如何高效地拼接字符串?

在Go語言中,最高效的方式拼接字符串是使用strings.Builderbytes.Buffer。這兩者都能夠避免在拼接過程中多次創建和複製字符串,因此它們比普通的++=運算符更加高效。

以下是一個使用strings.Builder的例子:

package main

import (
    "strings"
    "fmt"
)

func main() {
    var builder strings.Builder

    for i := 0; i < 10; i++ {
        builder.WriteString("Go ")
    }

    result := builder.String() // Get the concatenated string
    fmt.Println(result)
}

在這個例子中,我們創建了一個strings.Builder對象,並使用WriteString方法向其寫入字符串。最後,我們調用String方法獲取最終拼接的字符串。

同樣,我們可以使用bytes.Buffer達到類似的效果:

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer

    for i := 0; i < 10; i++ {
        buffer.WriteString("Go ")
    }

    result := buffer.String() // Get the concatenated string
    fmt.Println(result)
}

這兩種方式都可以有效地拼接字符串,而不會像++=那樣造成大量的內存分配和複製。在處理大量字符串拼接時,這可以帶來顯著的性能提升。

Golang中2 個 interface 可以比較嗎?

在 Go 語言中,兩個接口類型的變量可以比較,但有一些規則和限制:

  1. nil 接口比較:兩個 nil 接口值是相等的。

  2. 非 nil 接口比較:如果兩個接口值的動態類型相同,並且動態值也相等,那麼這兩個接口值就被認爲是相等的。

  3. 限制:如果接口的動態值是不可比較的類型(如切片),那麼在嘗試比較接口值時將會導致運行時錯誤。

下面是一些示例:

type Data struct {
    num int
}

var i, j interface{}
fmt.Println(i == j) // 輸出:true

i = 10
j = 10
fmt.Println(i == j) // 輸出:true

i = Data{num: 10}
j = Data{num: 10}
fmt.Println(i == j) // 輸出:true

i = []int{1, 2, 3}
j = []int{1, 2, 3}
fmt.Println(i == j) // 運行時錯誤:slices can only be compared to nil

總的來說,可以比較兩個接口值,但你需要確保接口的動態值是可比較的類型,否則會導致運行時錯誤。

Golang中init() 函數是什麼時候執行的?

在 Go 語言中,init() 函數是一種特殊的函數,它在每個包完成初始化後自動執行。這意味着,你不能在代碼中顯式地調用 init() 函數,它由 Go 運行時系統自動調用。初始化順序爲:

  1. 如果一個包被導入多次,init() 函數只會被執行一次。

  2. 包的初始化順序爲:首先初始化包級別(Package Level)的變量,然後是 init() 函數。如果一個包導入了其他包,會先初始化被導入的包。

  3. 即使一個包被多個其他包導入,它的 init() 函數也只會被執行一次。

  4. 在同一個包內,多個 init() 函數的執行順序爲它們在 Go 語言中,init() 函數是一種特殊的函數,它在每個包完成初始化後自動執行。這意味着,你不能在代碼中顯式地調用 init() 函數,它由 Go 運行時系統自動調用。初始化順序爲:

  5. 如果一個包被導入多次,init() 函數只會被執行一次。

  6. 包的初始化順序爲:首先初始化包級別(Package Level)的變量,然後是 init() 函數。如果一個包導入了其他包,會先初始化被導入的包。

  7. 即使一個包被多個其他包導入,它的 init() 函數也只會被執行一次。

  8. 在同一個包內,多個 init() 函數的執行順序爲它們在代碼中的出現順序。

這是一個簡單的例子:

package main

import "fmt"

var foo = initFoo()

func initFoo() int {
    fmt.Println("Initializing variable...")
    return 42
}

func init() {
    fmt.Println("Executing init function...")
}

func main() {
    fmt.Println("Executing main function...")
    fmt.Println("Foo:", foo)
}

在這個例子中,程序的輸出會是:

Initializing variable...
Executing init function...
Executing main function...
Foo: 42

這顯示了 Go 語言初始化的順序:首先初始化包級別的變量(在這裏是 foo),然後執行 init() 函數,最後是 main() 函數。

Golang中如何比較兩個 map 是否相等?

Go語言的標準庫中沒有直接提供比較兩個map是否相等的函數,所以我們需要自己編寫函數來實現這個功能。在比較兩個map是否相等時,我們需要檢查兩個map的長度是否相等,然後檢查每個鍵在兩個map中都存在,並且對應的值也相等。

下面是一個簡單的函數,用於比較兩個map[string]int是否相等:

package main

import "fmt"

func mapsEqual(a, b map[string]int) bool {
    if len(a) != len(b) {
        return false
    }

    for k, v := range a {
        if vb, ok := b[k]; !ok || vb != v {
            return false
        }
    }

    return true
}

func main() {
    map1 := map[string]int{"one": 1, "two": 2}
    map2 := map[string]int{"one": 1, "two": 2}

    fmt.Println(mapsEqual(map1, map2))  // 輸出 true
}

在這個例子中,mapsEqual函數首先檢查兩個map的長度是否相等。然後,它遍歷map a的每個鍵值對,檢查該鍵在map b中是否存在,以及map b中的值是否與map a中的值相等。如果所有鍵值對都匹配,那麼函數就返回true,表示兩個map相等。否則,返回false

是否可以對Golang中的map元素取地址?

在Go語言中,map的元素並不是變量,因此你不能直接獲取map元素的地址。嘗試這樣做會導致編譯錯誤。例如,以下代碼將無法編譯:

package main

import "fmt"

func main() {
    myMap := map[string]int{
        "foo": 42,
    }

    addr := &myMap["foo"] // 編譯錯誤:cannot take the address of myMap["foo"]
    fmt.Println(addr)
}

這是因爲map的元素可能會因爲新元素的添加或者map的擴容而被移動,所以直接獲取map元素的地址可能會引用到錯誤的元素。

如果你需要修改map中的元素,你可以使用替換的方式:

package main

import "fmt"

func main() {
    myMap := map[string]int{
        "foo": 42,
    }

    myMap["foo"] = 43
    fmt.Println(myMap) // 輸出:map[foo:43]
}

如果你需要一個可以取地址的map元素,你可以將map的值設置爲一個包含所需元素的結構體或者指向該元素的指針:

package main

import "fmt"

func main() {
    myMap := map[string]*int{}
    val := 42
    myMap["foo"] = &val

    addr := myMap["foo"]
    fmt.Println(*addr) // 輸出:42
}

在這個例子中,我們創建了一個map,它的值是整數指針。然後,我們可以獲取和修改這些值的地址。

在Golang中,Map可以邊遍歷邊刪除元素嗎?

在 Go 語言中,可以在遍歷 map 的過程中刪除元素。Go 的官方文檔明確指出:“在迭代過程中,刪除迭代器返回的映射項是安全的。”這是因爲,刪除操作不會影響迭代器的狀態。

以下是一個例子:

m := map[int]string{
    1: "a",
    2: "b",
    3: "c",
    4: "d",
}

for k := range m {
    if k == 1 {
        delete(m, k)
    }
}

在這個例子中,我們在遍歷過程中刪除了鍵爲 1 的元素,這是完全安全的。

然而,需要注意的是,map 的遍歷順序在 Go 中是不確定的。所以,你不能預測或依賴於遍歷的順序,除非你使用某種方式對鍵進行排序。

Golang中的float類型可以作爲Map的key嗎?

在 Go 語言中,浮點類型(float32float64)可以作爲 map 的鍵(key),但這並不是一個好的實踐。原因在於浮點數的精度問題和比較的複雜性。

浮點數的比較可能會引入微小的誤差,這可能導致意料之外的結果。即使兩個浮點數看起來相等,但由於精度問題,它們可能在內存中的表示是不同的。這就意味着,即使你使用看似相同的鍵來訪問 map,你可能得到不同的結果。

這是一個例子:

package main

import "fmt"

func main() {
    m := make(map[float64]string)
    
    m[0.1+0.2] = "value1"
    m[0.3] = "value2"
    
    fmt.Println(m[0.1+0.2]) // 輸出:"value1"
    fmt.Println(m[0.3]) // 輸出:"value2"
}

儘管 0.1+0.20.3 在數學上是相等的,但在浮點數的世界中,由於精度問題,它們可能不相等。所以,儘管它們看起來應該映射到同一個值,但在這個例子中,它們映射到了兩個不同的值。

因此,通常建議使用更穩定、更可預測的數據類型(例如整型或字符串)作爲 map 的鍵。

請問Golang中的map的key爲什麼是無序的?

Go 語言中的 map 數據結構是基於哈希表實現的。哈希表是一種數據結構,它通過使用哈希函數將鍵(key)映射到存儲位置。這種映射過程使得查找元素的速度非常快,幾乎與 map 的大小無關。

然而,這種映射過程並不保證元素的順序。當你向 map 添加新元素時,如果發生哈希衝突(即兩個或更多的 key 被哈希到同一個存儲位置),哈希表可能需要重新分配更多的空間,並重新哈希所有的元素以避免衝突。這個過程可能會導致元素的順序發生變化。

此外,Go 還有意地在每次運行程序時使用不同的哈希種子,以增加 map 的安全性並避免某些類型的攻擊。這意味着即使你使用相同的鍵集合,每次運行程序時 map 的元素順序也可能會改變。

因此,Go 語言中的 map 數據結構並不保證元素的順序,遍歷 map 的結果是無序的。如果你需要有序的鍵值對,你可能需要使用其他的數據結構,如排序的切片或者專門的有序 map 庫。

能介紹一下Golang中的map的擴容機制嗎?

Go語言的map實際上是一個哈希表,它的大小會動態變化。當map的元素數量達到一定閾值時,就會觸發擴容操作,即重新分配更大的內存空間,並將所有的元素重新哈希到新的內存空間中。

具體來說,Go語言的map擴容規則如下:

  1. 初始的map大小是0。當第一次添加元素時,map的大小會增加到8。

  2. map的元素數量超過其大小的6.5倍時,或者已經存儲的元素數量超過了2^15(32768)時,map的大小會翻倍。

  3. map的最大大小受限於地址空間的大小和指針的大小。在32位系統中,最大大小約爲231,而在64位系統中,最大大小約爲250。

這種設計使得map在添加新元素時仍能保持較好的性能,但也意味着添加元素可能需要重新哈希所有的元素,這可能會暫時阻塞map的其他操作。

因此,如果你知道最終需要存儲的元素數量,那麼在創建map時預先設置一個足夠大的容量會更加高效,因爲這樣可以避免多次擴容操作。例如:

myMap := make(map[string]int, 10000)

以上代碼創建了一個預期容量爲10000的map,如果實際元素數量不超過這個值,那麼就不會觸發擴容操作。

Golang中Map的數據結構是什麼?

Go語言中的 map 是一種哈希表數據結構,也就是鍵值對的集合。它的底層實現包括數組、哈希函數、鏈接等關鍵組成部分。

  1. 數組(Array):數組是 map 的核心組成部分,用於存儲鍵值對(bucket)。每個 bucket 可以存儲一到八個鍵值對。

  2. 哈希函數(Hash Function):哈希函數接收一個鍵並返回一個整數。這個整數被用來確定鍵值對應該存儲在哪個 bucket 中。

  3. 鏈接(Linking):如果兩個或更多的鍵哈希到同一個 bucket,那麼它們會被鏈接在一起。這就是所謂的哈希衝突。爲了解決這個問題,Go 的 map 使用了鏈接技術,也就是說,它在同一個 bucket 中存儲了一個鍵值對的鏈表。

以下是一個簡單的例子:

package main

import "fmt"

func main() {
    // 創建一個空的 map
    m := make(map[string]int)

    // 添加鍵值對
    m["apple"] = 1
    m["banana"] = 2

    // 獲取和打印鍵值對
    fmt.Println(m["apple"])  // 輸出:1
    fmt.Println(m["banana"]) // 輸出:2
}

在這個例子中,我們創建了一個空的 map,然後添加了兩個鍵值對。當我們從 map 中獲取一個值時,Go 使用哈希函數確定鍵的哈希值,然後在對應的 bucket 中查找鍵值對。

需要注意的是,Go 的 map 是動態大小的。當向 map 中添加更多的鍵值對時,如果當前的數組容量不足以容納更多的數據,Go 就會創建一個新的、更大的數組,並把舊的數據複製到新的數組中。這個過程被稱爲重新哈希(rehashing)。

在Golang中,任意類型T()都能夠調用*T的方法嗎?反過來呢?

在 Go 語言中,對於一個給定的類型 T,接收者爲 T 的方法可以被 T 類型的值和 *T 類型的指針調用。這是因爲 Go 在嘗試匹配方法接收者的類型時會自動做取址或解引用的操作。

例如:

type MyType int

func (m MyType) ValueMethod() {
    fmt.Println("ValueMethod called")
}

func (m *MyType) PointerMethod() {
    fmt.Println("PointerMethod called")
}

var v MyType
var p = &v

v.ValueMethod()    // 正常調用
p.ValueMethod()    // 正常調用,Go 自動將 p 解引用

v.PointerMethod()  // 正常調用,Go 自動取 v 的地址
p.PointerMethod()  // 正常調用

然而,如果 T 是一個接口類型,情況就有所不同。接口類型的值不能調用接口類型的指針的方法。

總的來說,對於非接口類型 T*T,它們可以調用彼此的方法。但對於接口類型,值類型接口不能調用指針類型接口的方法。這是因爲接口類型的值和指針遵循不同的規則。

由於內容太多,更多內容以鏈接形勢給大家,點擊進去就是答案了

20. 請問在Golang中,函數返回局部變量的指針是否安全?

21. 在Golang中,兩個nil可能不相等嗎?

22. 在Golang中,map賦值的過程是什麼樣的?

23. Golang如何實現兩種 get 操作?

24. Golang的切片作爲函數參數是值傳遞還是引用傳遞?

25. Golang中哪些不能作爲map類型的key?

26. Golang中nil map 和空 map 的區別是什麼?

27. 在Golang中,刪除一個key後,它的內存會被釋放嗎?

28. 使用map時需要注意哪些點?是否併發安全?

29. Golang 調用函數傳入結構體時,應該傳值還是指針?

30. 在Golang中如何解析tag?

31. 簡述一下Go的 rune 類型?

32. 能介紹一下sync.Map的用法嗎?

33. 在Go語言中,Struct能不能比較 ?

34. 在Go語言中,值接收者和指針接收者的區別是什麼?

35. 闡述Go有哪些數據類型?

36. 函數返回局部變量的指針是否安全?

37. 解釋array和slice的區別 ?

38. 解釋一下,在Go語言中什麼是負載因子?

39. Go 語言map和sync.Map誰的性能最好 ?

40. Go 的 chan 底層數據結構和主要使用場景 ?

41. Go 多返回值怎麼實現的?

42. Go 中 init 函數的特徵?

43. 請說一下Go 中 uintptr 和 unsafe.Pointer 的區別?

44. 簡述一下Golang空結構體 struct{} 的使用 ?

45. 簡述一下Golang中兩個變量值的4種交換方式?

46. 可以修改string類型的值嗎?

47. Switch 中如何強制執行下一個 case 代碼塊 ?

48. 如何關閉 HTTP 的響應體?

49. 當解析 JSON 數據時,默認將數值當做哪種類型?

50. 如何從 panic 中恢復 ?

51. 如何初始化帶嵌套結構的結構體 ?

52. 闡述一下Printf()、Sprintf()、Fprintf()函數的區別和用法?

53. 闡述一下Go 如何Array 類型的值作爲函數參數 ?

54. 闡述一下Go語言裏面的類型斷言 ?

55. 在Go語言中,局部變量和全局變量的缺省值是什麼?

56. 解釋一下Go語言中的靜態類型聲明 ?

57. 簡述一下Golang中的可變參數 ?

58. nil interface 和 nil interface 有什麼區別 ?

59. Golang導入包時,爲什麼可能使用’ _’ /’ .'導入? 舉例說明

60. 在Golang中,接口類型是否支持像Java那樣的多繼承?

61. Golang中的sync包是什麼?如何使用?

62. Golang中的sync.WaitGroup是什麼?

63. 簡述一下Golang的schedule函數 ?

64. 簡述一下全局運行隊列中獲取goroutine ?

65. 簡述一下如何從工作線程本地運⾏隊列中獲取goroutine ?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章