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

删除 mapkey 的语法是 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~~~

上一篇:Go基础语法(五)


下一篇:Python高级知识点学习(四)