天天看點

Go基礎文法(四)

可變參數函數

可變參數函數是一種參數個數可變的函數。

如果函數最後一個參數被記作 ...T ,這時函數可以接受任意個 T 類型參數作為最後一個參數。

隻有函數的最後一個參數才允許是可變的。

package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true
        }
    }
    if !found {
        fmt.Println(num, "not found in ", nums)
    }
    fmt.Printf("\n")
}
func main() {
    find(89, 89, 90, 95)
    find(87)
}
           

可變參數函數的

工作原理是把可變參數轉換為一個新的切片

是以以上代碼中這三個參數被編譯器轉換為一個 int 類型切片 int []int{89, 90, 95} 然後被傳入 find函數。

在上面代碼中,find 函數僅有一個參數時,我們沒有給可變參數 nums ...int 傳入任何參數。這也是合法的,在這種情況下 nums 是一個長度和容量為 0 的 nil 切片。

給可變參數函數傳入切片

直接給可變參數函數傳入切片,這種情況下無法通過編譯,編譯器報出錯誤

main.go:23: cannot use nums (type []int) as type int in argument to find 。

在上邊的代碼中可以看到,這些可變參數會被轉換為 int 類型切片然後再傳入 find 函數中,而如果傳入的已經是一個 int 類型切片,

編譯器試圖在 nums 基礎上再建立一個切片,像下面這樣:

nums := []int{89, 90, 95}
find(89, []int{nums})
           

這顯然是錯誤的。

如果非要直接傳入切片,有一個可以直接将切片傳入可變參數函數的文法糖,你可以在在切片後加上 ... 字尾。如果這樣做,切片将直接傳入函數,不再建立新的切片。

func main() {
    nums := []int{89, 90, 95}
    find(89, nums...)
}
           
易錯點1

看下邊代碼:

package main

import (
    "fmt"
)

func change(s ...string) {  
    s[0] = "Go"
}

func main() {
    welcome := []string{"hello", "world"}
    change(welcome...)
    fmt.Println(welcome)
}
           

如果使用了 ... ,welcome 切片本身會作為參數直接傳入,不需要再建立一個新的切片。這樣參數 welcome 将作為參數傳入 change 函數

在 change 函數中,切片的第一個元素被替換成 Go,這樣程式産生了下面的輸出值:

[Go world]
           
易錯點2

繼續看代碼:

package main

import (
    "fmt"
)

func change(s ...string) {
    s[0] = "Go"
    s = append(s, "playground")
    fmt.Println(s)
}

func main() {
    welcome := []string{"hello", "world"}
    change(welcome...)
    fmt.Println(welcome)
}

運作結果:
[Go world playground]
[Go world]
           

在最初的時候有一句話:GO 語言的參數傳遞都是 值傳遞。

這裡就是考究的對這句話的了解。 還有就是對slice的了解。

slice 包含 3部分: 長度、容量和指向數組第零個元素的指針 所謂的值傳遞怎麼了解呢,就是傳遞slice 的時候,把這三個值拷一個副本,傳遞過去。注意:指針作為值拷貝的副本,指向的是同一個位址,是以修改位址的内容時,原slice也就随之改變。 反之,對拷貝slice副本的修改,如:append,改變的是副本的len、cap,原slice的len、cap并不受影響。

Maps

  • map 是在 Go 中将鍵(key)與值(value)關聯的内置類型。通過相應的鍵可以擷取到值。
//建立 map 的文法。
make(map[type of key]type of value) 

//建立了一個名為 personSalary 的 map,鍵是 string 類型,而值是 int 類型。
personSalary := make(map[string]int)
           

map 的零值是 nil。如果你想添加元素到 nil map 中,會觸發運作時 panic。是以 map 必須使用 make 函數初始化。

package main

import (
    "fmt"
)

func main() {  
    var personSalary map[string]int
    if personSalary == nil {
        fmt.Println("map is nil. Going to make one.")
        personSalary = make(map[string]int)
    }
}
           

給map添加元素

這裡map添加元素和python中dict很像,直接指派便可:

func main() {
    var personSalary map[string]int
    if personSalary == nil {
        fmt.Println("map is nil. Going to make one.")
        personSalary = make(map[string]int)
    }

    personSalary["num"] = 2
    personSalary["age"] = 24

    fmt.Println(personSalary)
}
           

你也可以在聲明的時候初始化 map:

package main

import (
    "fmt"
)

func main() {
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    employee := "jamie"
    fmt.Println("Salary of", employee, "is", personSalary[employee])
}
           

如果擷取一個不存在的元素,map 會傳回該元素類型的零值。

例如:在 personSalary 這個 map 裡,如果我們擷取一個不存在的元素,會傳回 int 類型的零值 0。

map中擷取不包含指定key時,不會産生運作錯誤。

判斷map中是否存在指定的key

value, ok := parMap["g"]

如果存在,ok=ture,value=對應的其值

如果不存在,ok=false,value=該map值得類型的零值

func main() {

    parMap := map[string]int{
        "name":2,
        "age":22,
    }
    fmt.Println(parMap)
    value, ok := parMap["g"]
    fmt.Println(value, ok)
    
}
           

周遊map

使用for := range周遊

for value, key := range parMap
package main

import (
    "fmt"
)

func main() {
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    fmt.Println("All items of a map")
    for key, value := range personSalary {
        fmt.Printf("personSalary[%s] = %d\n", key, value)
    }

}
           
有一點很重要,當使用 for range 周遊 map 時,不保證每次執行程式擷取的元素順序相同。

删除map中的key

删除

map

key

的文法是

delete(map, key)

。這個函數沒有傳回值。

package main

import (  
    "fmt"
)

func main() {  
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    fmt.Println("map before deletion", personSalary)
    delete(personSalary, "steve")
    fmt.Println("map after deletion", personSalary)

}
           

擷取map的長度

使用len()函數擷取map的長度

len(personSalary)

           

注意:

Map是引用類型,和 slices 類似。當 map 被指派為一個新變量的時候,它們指向同一個内部資料結構。是以,改變其中一個變量,就會影響到另一變量。
當 map 作為函數參數傳遞時也會發生同樣的情況。函數中對 map 的任何修改,對于外部的調用都是可見的。
map 之間不能使用 == 操作符判斷,== 隻能用來檢查 map 是否為 nil。會報錯: invalid operation: map1 == map2 (map can only be compared to nil)。

如果文章對您有幫助,記得點個贊,後續持續更新ing~~~