9 Go 语言循环语句 1, 概念 在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。 2, 分类 1. for 循环 : 重复执行语句块 a. 语法: for init; condition; post {} for condition {} for {} init: 一般为赋值表达式,给控制变量赋初值; condition: 关系表达式或逻辑表达式,循环控制条件; post: 一般为赋值表达式,给控制变量增量或减量。 b. 实例 for02.go package main import "fmt" func main() { sum := 0 for i := 0 ; i <= 10; i++ { sum += i } fmt.Println(sum) } for03.go package main import "fmt" func main() { sum :=1 for ; sum <=10 ; { sum +=sum } fmt.Println(sum) for sum <= 10 { sum +=sum } fmt.Println(sum) } c. For-each range 循环 这种格式的循环可以对字符串、数组、切片等进行迭代输出元素。 实例: for04.go package main import "fmt" func main() { strings := []string{"google","runoob"} for i,s :=range strings { fmt.Println(i,s) } numbers := [6]int{1,2,3,5} for i,x :=range numbers { fmt.Printf("第%d位置X的值为 %d\n", i , x) } num2 :=[]int{11,22,33} for i,x :=range num2 { fmt.Printf("第%d位置X的值为 %d\n" , i , x) } str := "abcdefghijk" for i,x :=range str { fmt.Printf("第%d位置X的值为 %c\n" , i , x) } } 2. 循环嵌套 : 在 for 循环中嵌套一个或多个 for 循环 实例: for05.go package main import "fmt" func main() { var i,j int for i=2; i< 100 ; i++ { for j=2;j<=(i/j);j++{ if(i%j==0){ break } } if(j > (i/j)){ fmt.Printf("%d 是素数\n",i) } } } for06.go package main import "fmt" func main() { for i :=1;i<=9;i++{ for j :=1;j<=i;j++{ fmt.Printf("%d x %d = %d \t",i,j,i*j) } fmt.Println() } } 3, 循环控制语句 1. 循环控制语句可以控制循环体内语句的执行过程。 2. 分类 break 语句: 经常用于中断当前 for 循环或跳出 switch 语句 用途: a. 用户跳出当前循环,并开始执行循环之外的语句 b. 在 switch 中跳出 case c. 在多重循环中,可以用标号 label 标出想要break的循环(label名称可以随便起) 实例: for07.go package main import "fmt" func main() { num := 10 for ;num <= 20; num++ { if num == 15 { break } fmt.Println(num) } } for09.go package main import "fmt" func main() { // 不使用标记 fmt.Println("------break-----") for i:=1;i<=3;i++{ fmt.Printf("i:%d\n",i) for i2 := 11; i2 <= 13 ; i2 ++ { fmt.Printf("i2:%d\n",i2) break } } // 使用标记 fmt.Println("------break label-----") re: for i := 1; i <= 3 ; i++ { fmt.Printf("i:%d\n",i) for i2 :=11 ; i2<=13;i2++ { fmt.Printf("i2:%d\n",i2) break re } } } continue 语句: 跳过当前循环的剩余语句,然后继续进行下一轮循环。 实例 for08.go package main import "fmt" func main() { num := 10 for ; num<=20 ; num++ { if num == 15 { continue } fmt.Println(num) } } for10.go package main import "fmt" func main() { // 不使用标记 fmt.Println("-------continue-------") for i := 1;i<=3;i++{ fmt.Printf("i:%d\n",i) for i2:=11;i2<=13;i2++{ fmt.Printf("i2:%d\n",i2) continue } } // 使用标记 fmt.Println("-------continue label-------") re: for i:=1;i<=3;i++{ fmt.Printf("i:%d\n",i) for i2:=11;i2<=13;i2++{ fmt.Printf("i2:%d\n",i2) continue re } } } goto 语句: 将控制转移到被标记的语句。 a. 说明: goto 语句可以无条件地转移到过程中指定的行。 goto 语句通常与条件语句配合使用。可用来实现条件转移,构成循环,跳出循环体等功能。 但是,在结构化程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难。 b. 实例: 4, 无限循环 1. 如果循环中条件语句永远不为 false 则会进行无限循环,我们可以通过 for 循环语句中只设置一个条件表达式来执行无限循环 2. 实例 for01.go package main import "fmt" func main() { for true { fmt.Printf("这是无限循环。\n") } } 10 Go 语言条件语句 1, 概念 条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为 true 来决定是否执行指定语句,并在条件为 false 的情况在执行另外的语句。 2, 分类 if 语句: if 语句 由一个布尔表达式后紧跟一个或多个语句组成。 实例: if01.go package main import "fmt" func main() { a := 10 if a < 20 { fmt.Printf("a 小于 20\n") } fmt.Printf("a 的值为 : %d\n", a) } if...else 语句: if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。 实例: if02.go package main import "fmt" func main() { var a int = 10 if a < 20 { fmt.Printf("a 小于 20\n") } else { fmt.Printf("a 大于 20\n") } fmt.Printf("a 的值为: %d\n",a) } if 嵌套语句: 你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。 实例: if03.go package main import "fmt" func main() { var a int=100 var b int=200 if a == 100 { if b == 200 { fmt.Printf("a 的值为:%d,b 的值为:%d\n",a,b) } } fmt.Printf("a 的值为:%d\n",a) fmt.Printf("b 的值为:%d\n",b) } if04.go package main import "fmt" func main() { var a int var b int fmt.Printf("请输入密码:\n") fmt.Scan(&a) if a == 123 { fmt.Printf("请再次输入密码:") fmt.Scan(&b) if b == 123 { fmt.Printf("密码正确") } else { fmt.Printf("密码不正确") } }else{ fmt.Printf("密码不正确") } } switch 语句: switch 语句用于基于不同条件执行不同动作。 实例: switch01.go package main import "fmt" func main() { var grade string = "B" var marks int = 90 switch marks { case 90: grade = "A" case 80: grade = "B" case 50,60,70: grade = "C" default: grade = "D" } switch { case grade == "A": fmt.Printf("优秀\n") case grade == "B", grade == "C": fmt.Printf("良好\n") case grade == "D": fmt.Printf("及格\n") case grade == "F": fmt.Printf("不及格\n") default: fmt.Printf("差\n") } fmt.Printf("你的等级是 %s \n", grade) } Type Switch switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。 实例: switch02.go package main import "fmt" func main() { var x interface{} switch i := x.(type) { case nil: fmt.Printf(" x 的类型: %T", i) case int: fmt.Printf(" x 的类型:int") case float64: fmt.Printf("x 是 float64型") case func(int) float64: fmt.Printf("x 是 func(int) 类型") case bool , string: fmt.Printf("x 是 bool 或 string 类型") } } fallthrough: 使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。 实例: switch03.go package main import "fmt" func main() { switch { case false: fmt.Println("1, case 条件为false") fallthrough case true: fmt.Println("2, case 条件为true") fallthrough case false: fmt.Println("3, case 条件为false") fallthrough case true: fmt.Println("4, case 条件为true") case false: fmt.Println("5, case 条件为false") fallthrough default: fmt.Println("6, 默认 case") } } 从以上代码输出的结果可以看出:switch 从第一个判断表达式为 true 的 case 开始执行,如果 case 带有 fallthrough,程序会继续执行下一条 case,且它不会去判断下一个 case 的表达式是否为 true。 select 语句: select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。 select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。 select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。 语法描述: 每个 case 都必须是一个通信 所有 channel 表达式都会被求值 所有被发送的表达式都会被求值 如果任意某个通信可以进行,它就执行,其他被忽略 如果有多个 case 都可以运行, Select 会随机公平地选出一个执行。其他不会执行。 否则: 1. 如果有 default 子句,则执行该语句。 2. 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。 实例: select01.go package main import "fmt" func main() { var c1,c2,c3 chan int var i1,i2 int select { case i1 = <-c1: fmt.Printf("received ",i1, "from c1\n") case c2 <- i2: fmt.Printf("sent ", i2, " to c2\n") case i3, ok :=(<-c3): if ok{ fmt.Printf("received ", i3 , "from c3\n") } else { fmt.Printf("c3 is closed\n") } default: fmt.Printf("no commuinication\n") } } select 会循环检测条件,如果有满足则执行并退出,否则一直循环检测。 select02.go package main import ( "fmt" "time" ) func Chann(ch chan int, stopCh chan bool){ var i int i = 10 for j:=0;j<10;j++{ ch <- i time.Sleep(time.Second) } stopCh <- true } func main() { ch := make(chan int) c :=0 stopCh := make(chan bool) go Chann(ch, stopCh) for { select { case c= <-ch: fmt.Println("Receive",c) fmt.Println("channel") case s :=<-ch: fmt.Println("Receive",s) case _ = <-stopCh: goto end } } end: } 注意:Go 没有三目运算符,所以不支持 ?: 形式的条件判断。 备注: goroutine: Go语言程序的并发体,channels 是它们之间的通信机制。 11 Go 语言函数 1,描述 函数是基本的代码块,用于执行一个任务。 Go 语言最少有个 main() 函数。 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。 函数声明告诉了编译器函数的名称,返回类型,和参数。 Go 语言标准库提供了多种可动用的内置的函数。例如,len() 函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回数组中包含的元素个数。 2,函数定义 func function_name( [parameter list] ) [return_types] { 函数体 } func:函数由 func 开始声明 function_name:函数名称,函数名和参数列表一起构成了函数签名。 parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。 return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。 函数体:函数定义的代码集合。 3,实例 func01.go package main import "fmt" func main() { var a int = 100 var b int = 200 var ret int ret = max(a,b) fmt.Printf("最大值是:%d\n", ret) } func max(num1 , num2 int ) int{ var result int if(num1 > num2){ result = num1 } else { result = num2 } return result } func02.go package main import "fmt" func swap(x,y string )(string,string){ return y,x } func main() { a,b := swap("Google","Runoob") fmt.Println(a,b) } 4, 函数参数 函数如果使用参数,该变量可成为函数的形参。 形参就像定义在函数体内的局部变量。 调用函数,可以通过两种方式来传递参数。 值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。 实例: func03.go package main import "fmt" func main() { a := 100 b := 200 fmt.Printf("交换前 a 的值为: %d\n",a) fmt.Printf("交换前 b 的值为: %d\n",b) swap(a,b) fmt.Printf("交换后 a 的值为:%d\n",a) fmt.Printf("交换后 b 的值为:%d\n",b) } func swap(x,y int) int { var tmp int tmp = x x = y y = tmp return tmp } 5, 函数用法 函数作为另外一个函数的实参: 函数定义后可作为另外一个函数的实参数传入 func05.go package main import ( "fmt" "math" ) func main(){ getSquareRoot := func(x float64) float64 { return math.Sqrt(x) } fmt.Println(getSquareRoot((9))) } 闭包: 闭包是匿名函数,可在动态编程中使用 func06.go package main import "fmt" func getSequence() func() int { i := 0 return func() int{ i++ return i } } func main() { nextNumber := getSequence() fmt.Println(nextNumber()) fmt.Println(nextNumber()) fmt.Println(nextNumber()) nextNumber1 := getSequence() fmt.Println(nextNumber1()) fmt.Println(nextNumber1()) } func07.go package main import "fmt" func main() { add_func := add(1,2) fmt.Println(add_func()) fmt.Println(add_func()) fmt.Println(add_func()) } func add(x1,x2 int) func()(int,int) { i := 0 return func() (int,int){ i++ return i , x1+x2 } } func08.go package main import "fmt" func main() { add_func := add(1,2) fmt.Println(add_func(1,1)) fmt.Println(add_func(0,0)) fmt.Println(add_func(2,2)) } func add(x1,x2 int) func(x3 int, x4 int)(int,int,int){ i := 0 return func(x3 int, x4 int)(int,int,int){ i++ return i,x1+x2,x3+x4 } } 方法: 方法就是一个包含了接受者的函数 func09.go package main import ( "fmt" ) /* 定义结构体 */ type Circle struct { radius float64 } func main() { var c1 Circle c1.radius = 10.00 fmt.Println("圆的面积 = ", c1.getArea()) } /* 该 method 属于 Circle 类型对象中的方法 */ func (c Circle) getArea() float64 { // c.radius 即为 Circle 类型对象中的熟悉 return 3.14 * c.radius * c.radius } 注意: go语言没有面向对象开发,但是这个方法配合结构体和面向对象开发类似。 12 Go 语言变量作用域 1, 概念: 作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。 换句话说:就是这个标识符可以在哪里使用 2,声明: 函数内定义的变量称为局部变量 scope01.go package main import "fmt" func main() { var a,b,c int a = 10 b = 20 c = a + b fmt.Printf("结果: a = %d , b = %d , c = %d",a,b,c) } 函数外定义的变量称为全局变量 scope02.go package main import "fmt" var g int func main() { var a,b int a = 10 b = 20 g = a + b fmt.Printf("结果: a = %d , b = %d , g = %d", a,b,g) } Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。 函数定义中的变量称为形式参数 scope03.go package main import "fmt" var a int = 20 ; func main() { var a int = 10 var b int = 20 var c int = 0 fmt.Printf("main()函数中 a= %d\n",a) c = sum(a,b) fmt.Printf("main()函数中 c=%d\n",c) } func sum(a,b int) int { fmt.Printf("sum()函数中 a=%d\n",a) fmt.Printf("sum()函数中 b=%d\n",b) return a + b } 3,初始化局部和全局变量 不同类型的局部和全局变量默认值为: int 0 float32 0 pointer nil 13 Go 语言数组 1,概念 Go 语言提供了数组类型的数据结构。 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。 数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。 2,声明数组 Go 语言数组声明需要指定元素类型以及元素个数 var variable_name [SIZE] variable_type 例子 var balance [10] float32 3,初始化数组 实例 var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} 初始化数组中 {} 中的元素个数不能大于 [] 中的数字。 如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小: 4,访问数组元素 var salary float32 = balance[9] 实例: list01.go package main import "fmt" func main() { var n [10] int var i,j int for i=0;i<10;i++{ n[i] = i + 100 } for j = 0 ; j<10;j++{ fmt.Printf("Element[%d] = %d\n" , j , n[j]) } var l = [5]int{1,2,3,3,4,} for m := 0;m<5 ; m++{ fmt.Println(l[m]) } } 5,更多内容 多维数组 Go 语言支持多维数组,最简单的多维数组是二维数组 a. 初始化二维数组 a = [3][4]int{ {0,1,2,3}, {4,5,6,7}, {8,9,10,11}, } 注意:以上代码中倒数第二行的 } 必须要有逗号,因为最后一行的 } 不能单独一行 实例: list02.go package main import "fmt" func main() { var a=[5][2]int{ {0,0}, {1,2}, {2,4}, {3,6}, {4,8}, } // {4,8}后面逗号不能去掉 for i:=0;i<5;i++{ for j:=0;j<2;j++{ fmt.Printf("a[%d][%d] = %d\n",i,j,a[i][j]) } } } 向函数传递数组 你可以向函数传递数组参数 如果你想向函数传递数组参数,你需要在函数定义时,声明形参为数组,我们可以通过以下两种方式来声明: 方式一: void myFunction(param [10]int){} 方式二: void myFunction(param []int){} 实例: list03.go package main import "fmt" func main() { var balance = [5]int{1000,2,3,17,50} var avg float32 /* 数组作为参数传递给函数 */ avg = getAverage(balance,5) /* 输出返回的平均值 */ fmt.Printf("平均值为:%f",avg) } func getAverage(arr [5]int, size int) float32 { var i , sum int var avg float32 for i=0;i<size;i++{ sum +=arr[i] } avg = float32(sum) / float32(size) return avg } 14 Go 语言指针 1,概念 Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。 变量是一种使用方便的占位符,用于引用计算机内存地址。 Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。 一个指针变量指向了一个值的内存地址。 类似于变量和常量,在使用指针前你需要声明指针。 var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。以下是有效的指针声明: var ip *int /* 指向整型 */ var fp *float32 /* 指向浮点型 */ 2,内存地址实例 pinter01.go package main import "fmt" func main() { var a int = 10 fmt.Printf("变量的地址:%x\n" , &a) } 3,如何使用指针 a. 指针使用流程 定义指针变量 为指针变量赋值 访问指针变量中指向地址的值 b. 实例 pointer02.go package main import "fmt" func main() { var a int = 20 /* 声明实际变量 */ var ip *int /* 声明指针变量 */ ip = &a /* 指针变量的存储地址 */ fmt.Printf("a 变量的地址是:%x\n",&a) /* 指针变量的存储地址 */ fmt.Printf("ip 变量存储的指针地址:%x\n",ip) /* 使用指针访问值 */ fmt.Printf("*ip 变量的值:%d\n", *ip) fmt.Printf("*&a 的值:%d\n",*&a) } 4,Go 空指针 当一个指针被定义后没有分配到任何变量时,它的值为 nil。 nil 指针也称为空指针。 nil 在概念上和其它语言的null/None/nil/NULL一样,都指代零值或空值。 一个指针变量通常缩写为 ptr 。 实例: pointer03.go package main import "fmt" func main() { var ptr *int fmt.Printf("ptr 的值为: %x\n",ptr) } 空指针判断: if(ptr != nil) /* ptr 不是空指针 */ if(ptr == nil) /* ptr 是空指针 */ 指针更多内容 Go 指针数组: 你可以定义一个指针数组来存储地址 pointerlist01.go package main import "fmt" const MAX int = 3 func main() { a := []int{10,100,200} var i int for i=0;i<MAX;i++{ fmt.Printf("a[%d] = %d\n",i,a[i]) } } ptr 为整型指针数组。因此每个元素都指向了一个值。以下实例的三个整数将存储在指针数组中: pointerlist01.go package main import "fmt" const MAX int = 3 func main() { a := []int{10,100,200} var i int var ptr [MAX]*int for i = 0;i<MAX;i++{ ptr[i] = &a[i] /* 整数地址赋值给指针数组 */ } for i=0;i<MAX;i++{ fmt.Printf("a[%d] = %d\n",i,*ptr[i]) } } Go 指向指针的指针: Go 支持指向指针的指针 如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。 当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址。 指针变量声明格式: var ptr **int 实例: pointerlist02.go package main import "fmt" func main() { var a int var ptr *int var pptr **int a = 3000 ptr = &a pptr = &ptr fmt.Printf("变量 a = %d\n",a) fmt.Printf("指针变量 *ptr = %d\n", *ptr) fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr) } Go 向函数传递指针参数: 通过引用或地址传参,在函数调用时可以改变其值 Go 语言允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可。 实例:向函数传递指针,并在函数调用后修改函数内的值 pointerfunc01.go package main import "fmt" func main() { var a int = 100 var b int = 200 fmt.Printf("交换前 a 的值: %d \n", a) fmt.Printf("交换前 b 的值: %d \n", b) /* 调用函数用于交换值 * &a 指向 a 变量的地址 * &b 指向 b 变量的地址 */ swap(&a,&b) fmt.Printf("交换后 a 的值: %d \n", a) fmt.Printf("交换后 b 的值: %d \n", b) } func swap(x *int, y *int){ var tmp int tmp = *x *x = *y *y = tmp } 15 Go 语言结构体 1,概念 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。 结构体表示一项记录,比如保存图书馆的书籍记录。 2,定义结构体 结构体定义需要使用 type 和 struct 语句。 struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。 格式: type struct_variable_type struct { member definition member definition ... member definition } 一旦定义了结构体类型,他就能用于变量的声明,语法格式如下: variable_name := structure_variable_type {value1,value2,...} variable_name := structure_variable_type {k1:v1,k2:v2,k3:v3} 实例: struct01.go package main import "fmt" type Books struct { title string author string subject string book_id int } func main() { // 创建一个新的结构体 fmt.Println(Books{"Go 语言","www.runoob.com","Go 语言教程", 1826262}) // 也可以使用 k=>v格式 fmt.Println(Books{title:"Go 语言",author:"www.runoob.com",subject:"Go 语言教程",book_id:1826262}) // 忽略的字段为0或空 fmt.Println(Books{title:"Go 语言",author:"www.runoob.com"}) } 3,访问结构体成员 如果要访问结构体成员,需要使用点号.操作符 实例: struct02.go package main import "fmt" type Books struct { title string author string subject string book_id int } func main() { var Book1 Books var Book2 Books Book1.title = "Go 语言" Book1.author = "www.runoob.com" Book1.subject = "Go 语言教程" Book1.book_id = 1826262 Book2.title = "Python教程" Book2.author = "www.runoob.com" Book2.subject = "Python 语言教程" Book2.book_id = 6262182 fmt.Printf("Book1 title: %s\n",Book1.title) fmt.Printf("Book1 author: %s\n",Book1.author) fmt.Printf("Book2 title: %s\n",Book2.title) fmt.Printf("Book2 author: %s\n",Book2.author) } 4,结构体作为函数参数 你可以像其他数据类型一样将结构体类型作为参数传递给函数。 struct03.go package main import "fmt" type Books struct { title string author string subject string book_id int } func main() { var Book1 Books var Book2 Books Book1.title = "Go 语言" Book1.author = "www.runoob.com" Book1.subject = "Go 语言教程" Book1.book_id = 6495407 /* book 2 描述 */ Book2.title = "Python 教程" Book2.author = "www.runoob.com" Book2.subject = "Python 语言教程" Book2.book_id = 6495700 /* 打印 Book1 信息 */ printBook(Book1) /* 打印 Book2 信息 */ printBook(Book2) } func printBook( book Books ) { fmt.Printf( "Book title : %s\n", book.title) fmt.Printf( "Book author : %s\n", book.author) fmt.Printf( "Book subject : %s\n", book.subject) fmt.Printf( "Book book_id : %d\n", book.book_id) } struct04.go package main import "fmt" type Student struct { name string age int classname string score int } func (s *Student) Totle() int { // 为 Student 类型绑定 Totle的方法。*Student为指针引用,可以修改传入参数的值 return s.score * 5 //方法归属于类型,不归属于具体的对象,声明该类型的对象即可调用该类型的方法 } func main() { var stu1 Student var stu2 Student stu1.name = "张三" stu1.age = 24 stu1.classname="初一" stu1.score = 89 stu2.name = "李四" stu2.age = 20 stu2.classname = "初二" stu2.score = 95 fmt.Printf(stu1.name,stu1.age,stu1.classname,stu1.score,stu1.Totle()) fmt.Printf(stu2.name,stu2.age,stu2.classname,stu2.score,stu2.Totle()) } 16 Go 语言切片 1, 概念 Go 语言切片是对数组的抽象。 Go 数组的长度不可改变,在特定场所中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。 2, 定义切片 你可以声明一个未指定大小的数组来定义切片 var identifier []type 切片不需要说明长度 或使用make()函数来创建切片 var slice1 []type = make([]type,len) 也可以简写为 slice1 := make([]type,len) 也可以指定容量,其中capacity为可选参数 make([]T,length,capacity) 这里 len 是数组的长度并且也是切片的初始长度。 3, 切片初始化 s := [] int{1,2,3} 直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是1,2,3,其cap=len=3 s := arr[:] 初始化切片s,是数组arr的引用 s := arr[starIndex:endIndex] 将arr中从下标startIndex 到 endIndex-1下的元素创建为一个新的切片 s := arr[startIndex:] s := arr[:endIndex] s1 := s[startIndex:endIndex] 通过内置函数make()初始化切片s,[]int 标识为其元素类型为int的切片 4, len() 和 cap() 函数 切片是可索引的,并且可以由len() 方法获取长度。 切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。 slice01.go package main import "fmt" func main() { var numbers = make([]int,3,7) printSlice(numbers) } func printSlice(x []int) { fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x) } 5, 空(nil)切片 一个切片在未初始化之前默认为nil,长度为0 slice02.go package main import "fmt" func main() { var numbers []int printSlice(numbers) if(numbers == nil){ fmt.Printf("切片是空的") } } func printSlice(x []int) { fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x) } 6, 切片截取 可以通过设置下限及上限来设置截取切片 [lower-bound:upper-bound] slice03.go package main import "fmt" func main() { numbers :=[]int{0,1,2,3,4,5,6,7,8} printSlice(numbers) /* 打印原始切片 */ fmt.Println("numbers == ", numbers) /* 打印子切片从索引1(包含)到索引4(不包含) */ fmt.Println("numbers[1:4] == ",numbers[1:4]) /* 默认下限为 0 */ fmt.Println("numbers[:3] == ", numbers[:3]) /* 默认上限为len(s) */ fmt.Println("numbers[4:] == ",numbers[4:]) numbers1 := make([]int,0,5) printSlice(numbers1) numbers2 := numbers[:2] printSlice(numbers2) numbers3 := numbers[2:5] printSlice(numbers3) } func printSlice(x []int) { fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x) } 7, append() 和 copy() 函数 如果想增加切片的容量,我们必须创建一个新的更大的切片把原分片的内容都拷贝过来。 下面的代码描述了从拷贝切片的copy方法到向切片追加新元素的append方法。 slice04.go package main import "fmt" func main() { var numbers []int printSlice(numbers) /* 允许追加空切片 */ numbers = append(numbers,0) printSlice(numbers) /* 向切片添加一个元素 */ numbers = append(numbers,1) printSlice(numbers) /* 同时添加多个元素 */ numbers = append(numbers,2,3,4) printSlice(numbers) /* 创建切片 numbers1 是之前切片的两倍容量 */ numbers1 := make([]int,len(numbers),(cap(numbers))*2) /* 拷贝 numbers 的内容到 numbers1 */ copy(numbers1,numbers) printSlice(numbers1) } func printSlice(x []int) { fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x) } 8, 补充:容量 切片拥有长度和容量 切片的长度是它所包含的元素个数 切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。 切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取。
来源:CSDN
作者:mx_steve
链接:https://blog.csdn.net/mx_steve/article/details/104037984