内置函数
// 1. close:主要用来关闭channel // 2. len:用来求长度,比如string、array、slice、map、channel // 3. new:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针 // 4. make:用来分配内存,主要用来分配引用类型,比如chan、map、slice // 5. append:用来追加元素到数组、slice中
示例如下:
// new 示例: package main import "fmt" func main(){ var i int fmt.Println(i) j := new(int) fmt.Println(j) *j = 100 fmt.Println(*j) } // 运行结果如下: [root@NEO example01_new]# go run main/main.go 0 0xc0000160b0 100 [root@NEO example01_new]# // append 示例: package main import "fmt" func main(){ var a []int // [] 中不写数字表示是一个切片 slice a = append(a,1,2) // append 中也是可变参数 fmt.Println(a) a = append(a,a...) // 添加一个切片;a...表示 切片a 中的所有元素 fmt.Println(a) } // 运行结果如下: [root@NEO example01_append]# go run main/main.go [1 2] [1 2 1 2] [root@NEO example01_append]# // recover 示例: package main import "fmt" func test(){ defer func(){ // func(){} 是匿名函数; func(){...}() 执行匿名函数 if err := recover(); err != nil{ // recover() 是捕获异常 fmt.Println(err) } }() a := 0 b := 1/a fmt.Println(b) return } func main(){ test() fmt.Println("hello world") } // 运行结果如下: [root@NEO example01_recover]# go run main/main.go runtime error: integer divide by zero hello world [root@NEO example01_recover]#
递归函数
一个函数调用自己,就叫做递归。示例代码如下:
// 示例代码1: package main import ( "fmt" ) func calc(n int) int { if n == 1 { return 1 } return calc(n-1) * n } func main() { n := calc(5) fmt.Println(n) } // 示例2:斐波那契数 package main import "fmt" func fab(n int) int { if n <= 1 { return 1 } return fab(n-1)+fab(n-2) } func main(){ n := fab(10) fmt.Println(n) }
递归的设计原则
1)一个大的问题能够分解成相似的小问题 2)定义好出口条件
闭包
闭包:一个函数和与其相关的引用环境组合而成的实体。示例如下:
// 示例代码: package main import "fmt" func Adder() func(int) int { // 函数 Adder 的返回值是也一个函数 var x int return func(d int) int { // 该处的 return 要和上面定义的返回值类型的 return 的函数一样 x += d return x } } func main() { f := Adder() // f 是一个函数 fmt.Println("f(1)",f(1)) // 此时 x 的值为默认的 0 fmt.Println("f(10)",f(10)) // 此时 x 的值变成了 1 fmt.Println("f(100)",f(100)) // 此时 x 的值变成了 10 } // 运行结果如下: [root@NEO example03_closure]# go run main/main.go f(1) 1 f(10) 11 f(100) 111 [root@NEO example03_closure]#
数组和切片
// 1. 数组:是同一种数据类型的固定长度的序列。 // 2. 数组定义:var a [len]int,比如:var a[5]int,一旦定义,长度不能变;元素的值默认为0 // 3. 长度是数组类型的一部分,因此,var a[5] int和var a[10]int是不同的类型 // 4. 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1 for i := 0; i < len(a); i++ { } for index, v := range a { } // 5. 访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic // 6. 数组是值类型,因此改变副本的值,不会改变本身的值 arr2 := arr1 arr2[2] = 100
数组的初始化
1. var age0 [5]int = [5]int{1,2,3} // 定义的时候初始化 2. var age1 = [5]int{1,2,3,4,5} 3. var age2 = […]int{1,2,3,4,5,6} // ... 的作用:编译器会自动帮你数里面有几个元素,然后就是长度为多少的数组 4. var str = [5]string{3:”hello world”, 4:”tom”} // 定义时指定下标对应的元素
多维数组
1. var age [5][3]int // 二维数组:可理解成5行3列 2. var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}} // ... 表示 编译器自己去数有多少行
多维数组遍历
// 示例代码: package main import "fmt" func test(){ var arr [2][5]int = [...][5]int{{1,2,3,4,5},{6,7,8,9,10}} for row,v_row := range arr{ for col,v_col := range v_row { fmt.Printf("(%d,%d)=%d ",row,col,v_col) } fmt.Println() } } func main(){ test() } // 运行结果如下: [root@NEO example04_multi_dim_arr]# go run main/main.go (0,0)=1 (0,1)=2 (0,2)=3 (0,3)=4 (0,4)=5 (1,0)=6 (1,1)=7 (1,2)=8 (1,3)=9 (1,4)=10 [root@NEO example04_multi_dim_arr]#
切片
// 1. 切片:切片是数组的一个引用,因此切片是引用类型;把一个切片传入函数中修改切片中元素的值,那么该切片在函数外的值也会改变,数组则不会 // 2. 切片的长度可以改变,因此,切片是一个可变的数组 // 3. 切片遍历方式和数组一样,并且可以用len()求长度 // 4. cap可以求出slice最大的容量,0 <= len(slice) <= cap(array),其中array是slice引用的数组 // 5. 切片的定义:var 变量名 []类型,比如 var str []string 和 var arr []int (这种方式只是定义了切片,但并没有对切片初始化,所以此时不能直接 arr[0]=1 这样赋值)
示例如下:
// 切片是引用类型的示例1: package main import "fmt" func modifySlice(a []int){ // 该函数的需要传入的参数是切片类型;slice map 和 chan 类型的参数传入的就是地址 a[1] = 100 // 修改 切片 a 的元素的值后,函数外 a 的值也会改变 } func testSlice(){ var s []int = []int{1,2,3} modifySlice(s) // 切片是引用类型,是数组的一个引用(可理解成切片是一个地址);此函数传了一个引用(引用中包含指针);可理解成给该函数传了一个地址 fmt.Println(s) } func main(){ testSlice() } // 运行结果如下: [root@NEO example05_slice_ref_type]# go run main/main.go [1 100 3] // 函数外切片的值也发生了改变 [root@NEO example05_slice_ref_type]# // 切片是引用类型的示例2: package main import "fmt" func testSliceRefArr(){ var a = [10]int{1,2,3} // 声明并初始化一个数组 b := a[1:4] // 声明并初始化一个切片 fmt.Printf("%p\n",b) // %p 表示十六进制表示,可用于打印一个地址 fmt.Printf("%p\n",&a[1]) // 数组 a 第一个元素的地址 } func main(){ testSliceRefArr() } // 运行结果如下: [root@NEO example05_slice_ref_arr]# go run main/main.go 0xc000064008 0xc000064008 // 切片 b 的地址和 数组a第一个元素的地址是一样的;所以 切片是一个地址 [root@NEO example05_slice_ref_arr]# // 示例代码: package main import "fmt" func testSlice(){ var slice []int // 声明一个数组;只是定义了数组,但并没有对切片初始化,所以此时不能直接 arr[0]=1 这样赋值 var arr [5]int = [...]int{1,2,3,4,5} // 声明并初始化一个数组 slice = arr[2:5] // 对切片初始化; 顾首不顾尾;可简写成 arr[2:] fmt.Println(slice) fmt.Println("len:",len(slice)) fmt.Println("cap:",cap(slice)) slice = slice[0:1] fmt.Println("len:",len(slice)) fmt.Println("cap:",cap(slice)) } func main(){ testSlice() } // slice、map、channel 都可以用 make 来初始化 // 运行结果如下: [root@NEO example05_slice01]# go run main/main.go [3 4 5] len: 3 cap: 3 len: 1 cap: 3 [root@NEO example05_slice01]#
切片的创建方式1:通过 数组 创建
// 1. 切片初始化:var slice []int = arr[start:end] ;包含start到end之间的元素,但不包含end // 2. var slice []int = arr[0:end]可以简写为 var slice []int=arr[:end] // 3. var slice []int = arr[start:len(arr)] 可以简写为 var slice[]int = arr[start:] // 4. Var slice []int = arr[0, len(arr)] 可以简写为 var slice[]int = arr[:] // 5. 如果要切片最后一个元素去掉,可以这么写: Slice = slice[:len(slice)-1]
切片的创建方式2: 通过make来创建切片
var slice []type = make([]type, len) slice := make([]type, len) slice := make([]type, len, cap)
用append内置函数操作切片
扫描二维码关注公众号,回复:
6851174 查看本文章
// 示例: slice = append(slice, 10) var a = []int{1,2,3} var b = []int{4,5,6} a = append(a, b…) // b... 表示 切片 b 中的所有元素 // append 的示例: package main import "fmt" func testSlice(){ var a [5]int = [...]int{1,2,3,4,5} b := a[1:] fmt.Printf("b=%p a[1]=%p\n",b,&a[1]) // 此时切片 b 的地址和 数组a第一个元素的地址是一样的 b[1] = 100 fmt.Println("before a:",a) // 此时 改变切片 b 的值 数组a 也会改变 b = append(b,10) b = append(b,10) b = append(b,10) b = append(b,10) b = append(b,10) b = append(b,10) // 添加了5个元素后,已经超过了切片 b 的容量 fmt.Println(b) fmt.Printf("b=%p a[1]=%p\n",b,&a[1]) // 此时切片 b 的地址和 数组a第一个元素的地址就不再一样;因为在声明并定义切片b时没有超过b的容量,此时b指向原来的数组,当超过b的容量后,系统会重新开辟一块内存,并把切片b原有的值放到新开辟的内存中,然再把追加的内容放进去 b[1] = 1000 fmt.Println("after a:",a) // 此时改变 b 值, a的值将不会改变,因为 切片 b 指向的内存地址已经不是 a 了 } func main(){ testSlice() // 切片是可变的,就是因为内部会根据容量的大小重新分配内存 } // 运行结果如下: [root@NEO example05_slice_beyond_cap]# go run main/main.go b=0xc000014158 a[1]=0xc000014158 before a: [1 2 100 4 5] // a 中对应的值也发生了改变 [2 100 4 5 10 10 10 10 10 10] b=0xc000062080 a[1]=0xc000014158 after a: [1 2 100 4 5] // 此时 a 中的值并没有改变 [root@NEO example05_slice_beyond_cap]#
切片resize
var a = []int {1,3,4,5} b := a[1:2] b = b[0:3]
切片拷贝:copy()
s1 := []int{1,2,3,4,5} s2 := make([]int, 10) copy(s2, s1) // 把 切片 s1 拷贝到 切片 s2 中;拷贝不会扩容 // 示例代码: package main import "fmt" func testCopy(){ var a []int = []int{1,2,3,4,5} b := make([]int,10) c := make([]int,1) copy(b,a) // 把a拷贝到b中 copy(c,a) // 把a拷贝到c中 fmt.Println(b) fmt.Println(c) // 拷贝不会扩容 } func main(){ testCopy() } // 运行结果如下: [root@NEO example05_slice_copy]# go run main/main.go [1 2 3 4 5 0 0 0 0 0] [1] [root@NEO example05_slice_copy]#
切片示例:使用非递归的方式实现斐波那契数列,打印前10个数。
// 示例代码如下: package main import "fmt" func fab(n int){ var a []int // 声明一个切片;[]中没有数字,所以是切片 a = make([]int,n) // 为切片a 分配内存 a[0] = 1 a[1] = 1 for i := 2; i < len(a); i++ { a[i] = a[i-1] + a[i-2] } for _,v := range a{ fmt.Println(v) } } func main() { fab(10) } // 运行结果如下: [root@NEO example04_fab_slice]# go run main/main.go 1 1 2 3 5 8 13 21 34 55 [root@NEO example04_fab_slice]#