《Go语言入门经典》4~6章读书笔记

第4章 函数

4.1 函数是什么

4.1.2 返回单个值

func isEven(i int) bool{
    return i % 2 == 0;
}

4.1.3 返回多个值

在Go语言中,可在函数签名中声明多个返回值,让函数返回多个结果。在这种情况下,终止语句可返回多个值。

func getPrize()(int, string){
    i := 2
    s := "goldfish"
    
    return i,s
}

调用这个函数时,可直接将返回值赋给变量并使用它们。

func main() {
    num, prize := getPrize();
    fmt.Println(num, prize)
}

4.2 定义不定参数函数

不定参数函数是参数数量不确定的函数。通俗地说,这意味着它们接受可变数量的参数。在Go语言中,能够传递可变数量的参数,但它们的类型必须与函数签名指定的类型相同。要指定不定参数,可使用3个点(…)。

在下面的示例中,函数签名指定函数可接受任意数量的int参数。

func sumNum(nums...int) int{
}

4.3 使用具名返回值

具名返回值让函数能够在返回前将值赋给具名变量,这有助于提升函数的可读性,使其功能更加明确。要使用具名返回值,可在函数签名的返回值部分指定变量名。

package main

import (
    "fmt"
)

func sayHi()(x string, y string){
    x = "hello"
    y = "world"
    return;
}

func main() {
    str1, str2 := sayHi();
    fmt.Println(str1)
    fmt.Println(str2)
}

4.4 使用递归函数

要在函数中实现递归,可将调用自己的代码作为终止语句中的返回值。

4.5 将函数作为值传递

Go将函数视为一种类型,因此可将函数赋给变量,以后再通过变量来调用它们。

package main

import (
    "fmt"
    "reflect"
)

func anotherFunction(f func() string) string{
    return f();
}

func main() {
    fn := func() string{
        return "function called"
    }

    fmt.Println(reflect.TypeOf(fn));
    fmt.Println(anotherFunction(fn));
}

结果如下

func() string
function called

函数anotherFunction的签名中包含一个子函数签名,这表明这个参数是一个返回字符串的函数。

第5章控制流程

5.2 使用else语句

func main() {
    var b = false;
    if b { 
        fmt.Println("b is true")
    } else {
        fmt.Println("b is false")
    }   
}
  • else不能单启一行,否则会报错。比如
if b{
}
else{
}
  • if判断中的b可以使用()括起来。

5.3 使用else if语句

func main() {
    var b int = 2;
    if (b == 1) {
        fmt.Println("b is 1")
    } else if b == 2{
        fmt.Println("b is 2")
    }
}

5.4 使用比较运算符

关于Go语言中的比较运算符,一个要点是两个操作数的类型必须相同。例如,无法对字符串和整数进行比较。

5.5 使用算术运算符

算术运算符也只能用于类型相同的操作数。

var a float32 = 1.1
var c int = 1;

fmt.Println(a + c)

运行时会报错

invalid operation: a + c (mismatched types float32 and int)

5.7 使用switch语句

func main() {
    fmt.Println("Hello, World!")
    i := 9
    switch i{
        case 2:
            fmt.Println("two")
        case 9:
            fmt.Println("nine")
        case 10:
            fmt.Println("ten")
        default:
            fmt.Println("what's wrong")
    }
}

不同于大多数语言,go的switch中没有break!

5.8 使用for语句进行循环

只包含条件的for语句

func main() {
    i := 0;
    for i<10{
        i++;
        fmt.Println("i is", i)
    }
}

5.8.1 包含初始化语句和后续语句的for语句

func main() {
    for i:=0; i<10; i++{
        fmt.Println("i is", i)
    }
}

注意,for之后的初始化及条件不能用()括号起来!

5.8.2 包含range子句的for语句

package main

import (
    "fmt"
)

func main() {
    numbers := []int{1,3,5,7}
    for i,n := range numbers{
        fmt.Printf("index is %d, value is %d\n", i, n)
    }
}

解读:

  • 声明变量numbers,并将一个包含4个整数的数组赋给它。
  • for语句指定了迭代变量i,用于存储索引值。这个变量将在每次迭代结束后更新。
  • for语句指定了迭代变量n,用于存储来自数组中的值。它也将在每次迭代结束后更新。

5.9 使用defer语句

defer能够让您在函数返回前执行另一个函数。函数在遇到return语句或到达函数末尾时返回。defer语句通常用于执行清理操作或确保操作(如网络调用)完成后再执行另一个函数。

func main() {
    defer fmt.Println("first defer")
    defer fmt.Println("second defer")
    defer fmt.Println("third defer")

    fmt.Println("Hello, World!")
}

结果:

Hello, World!
third defer
second defer
first defer

外部函数执行完毕后,按与defer语句出现顺序相反的顺序执行它们指定的函数。

第6章数组、切片和映射

6.1 使用数组

要创建数组,可声明一个数组变量,并指定其长度和数据类型。

var cheeses [2]string
  • 使用关键字var声明一个名为cheeses的变量。
  • 将一个长度为2的数组赋给这个变量。
  • 这个数组的类型为字符串。

6.2 使用切片

切片是底层数组中的一个连续片段,通过它您可以访问该数组中一系列带编号的元素。

为何要使用切片?

在Go语言中,使用数组存在一定的局限性。采用前面的数组cheeses表明方试,您无法在数组中添加元素;然而切片比数组更灵活,您可在切片中添加和删除元素,还可复制切片中的元素。可将切片视为轻量级的数组包装器,它既保留了数组的完整性,又比数组使用起来更容易。

要声明一个长度为2的空切片,可使用如下语法。

var cheeses = make([]string, 2)
  • 使用关键字var声明一个名为cheeses的变量。
  • 在等号右边,使用Go内置函数make创建一个切片,其中第一个参数为数据类型,而第二个参数为长度。在这里,创建的切片包含两个字符串元素。
  • 将切片赋给变量cheeses。

看下面这个例子

func main() {
    var cheeses = make([]string, 2)
    var books [2]string
    fmt.Println(reflect.TypeOf(cheeses), len(cheeses));
    fmt.Println(reflect.TypeOf(books), len(books));
}

输出

[]string 2
[2]string 2
  • books为数组,cheeses为切片
  • 两者长者均为2,但TypeOf的结果是有差别的。

6.2.1 在切片中添加元素

Go语言提供了内置函数append,让您能够增大切片的长度。append会在必要时调整切片的长度,但它对程序员隐藏了这种复杂性。

var books = make([]string, 2)
books = append(books, "book3");

函数append也是一个不定参数函数。这意味着使用函数append可在切片末尾添加很多值。

var books = make([]string, 2)
books = append(books, "b3", "b4", "b5");
fmt.Println(books, len(books));

结果

[  b3 b4 b5] 5

6.2.2 从切片中删除元素

要从切片中删除元素,也可使用内置函数append。在下面的示例中,删除了索引1处的元素。

package main

import (
    "fmt"
)

func main() {
    var books = make([]string, 3)
    books[0] = "b0";
    books[1] = "b1";
    books[2] = "b2";
    fmt.Println(books, len(books));
    
    var index int = 1;
    books = append(books[:index], books[index+1:]...);
    fmt.Println(books, len(books));
}

6.2.3 复制切片中的元素

要复制切片的全部或部分元素,可使用内置函数copy。在复制切片中的元素前,必须再声明一个类型与该切片相同的切片,例如,不能将字符串切片中的元素复制到整数切片中。

func main() {
    var books = make([]string, 3)
    books[0] = "b0";
    books[1] = "b1";
    books[2] = "b2";
    fmt.Println(books, len(books));
    
    var another = make([]string, 2)
    copy(another, books[])
    fmt.Println(another, len(another));
}
  • another长度只有2,所以copy后只含b0, b1两个元素。

函数copy在新切片中创建元素的副本,因此修改一个切片中的元素不会影响另一个切片。

还可将单个元素或特定范围内的元素复制到新切片中。

copy(another, books[1:])

上述代码从books的第1个元素开始复制。执行后,another中的元素为b1,b2

6.3 使用映射

数组和切片是可通过索引值访问的元素集合,而映射是通过键来访问的无序元素编组。映射在信息查找方面的效率非常高,因为可直接通过键来检索数据。简单地说,映射可视为键-值对集合。

只需一行代码就可声明并创建一个空映射。

var players = make(map[string]int) 

解读

  • 关键字var声明一个名为players的变量。
  • 在等号右边,使用Go语言内置函数make创建了一个映射,其键的类型为字符串,而值的类型为整数。
  • 将这个空映射赋给了变量players。

向映射中添加元素

func main() {
    var players = make(map[string]int) 
    players["sheep"] = 5 
    players["chicken"] = 2 
    players["mouse"] = 0
    fmt.Println(players)
}

注意:
做为key的字串必须使用双引号括起来,如果使用单引号会报错。

从映射中删除元素

delete(players, "mouse")

6.5 问与答

问:该使用数组还是切片?

答:除非确定必须使用数组,否则请使用切片。切片能够让您轻松地添加和删除元素,还无须处理内存分配问题。

问:没有从切片中删除元素的内置函数吗?

答:不能将delete用于切片。没有专门用于从切片中删除元素的函数,但可使用内置函数append来完成这种任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值