Go基础语法(四)

简介: 可变参数函数可变参数函数是一种参数个数可变的函数。如果函数最后一个参数被记作 ...T ,这时函数可以接受任意个 T 类型参数作为最后一个参数。只有函数的最后一个参数才允许是可变的。

可变参数函数

可变参数函数是一种参数个数可变的函数。

如果函数最后一个参数被记作 ...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~~~

目录
相关文章
|
7月前
|
XML 存储 JSON
10分钟上手Go语言结构体定义语法
10分钟上手Go语言结构体定义语法
43 0
|
3天前
|
Java Linux Go
一文带你速通Go语言基础语法
本文是关于Go语言的入门介绍,作者因其简洁高效的特性对Go语言情有独钟。文章首先概述了Go语言的优势,包括快速上手、并发编程简单、设计简洁且功能强大,以及丰富的标准库。接着,文章通过示例展示了如何编写和运行Go代码,包括声明包、导入包和输出语句。此外,还介绍了Go的语法基础,如变量类型(数字、字符串、布尔和复数)、变量赋值、类型转换和默认值。文章还涉及条件分支(if和switch)和循环结构(for)。最后,简要提到了Go函数的定义和多返回值特性,以及一些常见的Go命令。作者计划在后续文章中进一步探讨Go语言的其他方面。
10 0
|
11天前
|
Java Go 云计算
【Go语言专栏】Go语言语法基础详解
【4月更文挑战第30天】Go语言,因简洁、高效和并发处理能力深受开发者喜爱,尤其在云计算和微服务领域广泛应用。本文为初学者详解Go语法基础,包括静态类型、垃圾回收、并发编程、错误处理和包管理。通过学习,读者将理解Go语言设计哲学,掌握其语法,以提升开发效率。Go的并发核心是协程和通道,而错误处理采用显式方式,增强了代码的健壮性。Go的包管理机制支持模块化开发。了解这些基础,将助你更好地探索Go语言的世界及其未来潜力。
|
18天前
|
Go
Golang深入浅出之-Go语言基础语法:变量声明与赋值
【4月更文挑战第20天】本文介绍了Go语言中变量声明与赋值的基础知识,包括使用`var`关键字和简短声明`:=`的方式,以及多变量声明与赋值。强调了变量作用域、遮蔽、初始化与零值的重要性,并提醒读者注意类型推断时的一致性。了解这些概念有助于避免常见错误,提高编程技能和面试表现。
27 0
|
1月前
|
存储 Java 编译器
go语言基础语法
go语言基础语法
|
3月前
|
设计模式 缓存 JavaScript
盘点Go语言中那些酷酷的语法
盘点Go语言中那些酷酷的语法
23 0
|
3月前
|
Go 开发者
Go语言入门:环境搭建与基础语法
【2月更文挑战第1天】本文将引导读者从零开始接触Go语言,介绍如何搭建Go语言开发环境,并详细讲解Go语言的基础语法,包括变量、数据类型、运算符、控制流语句等。通过本文的学习,读者将能够掌握Go语言的基本编程知识,为后续深入学习打下坚实基础。
|
4月前
|
存储 Go C语言
go 基本语法
go 基本语法
33 0
|
5月前
|
存储 Go 索引
Go 语言中 For 循环:语法、使用方法和实例教程
for循环用于多次执行特定的代码块,每次都可以使用不同的值。每次循环执行都称为一次迭代。for循环可以包含最多三个语句: 语法
49 0
|
7月前
|
Go 开发者
长文回顾Go语言基础语法 新手进阶必读
长文回顾Go语言基础语法 新手进阶必读
23 0
长文回顾Go语言基础语法 新手进阶必读