第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来完成这种任务。
网友评论