一、循环
package main
import "fmt"
func main(){
sum := 0
for i:=1;i<=100;i++{
sum = sum + i
}
fmt.Println("sum = ",sum)
}
str := "abc"
for i := 0;i<len(str);i++{
fmt.Printf("str[%d] = %c\n",i,str[i])
}
//迭代打印每个元素,默认返回2个值。一个是元素位置,一个是元素本身
for i,data := range str{
fmt.Printf("str[%d] = %c\n",i,data)
}
- break:跳出循环,如果嵌套多个循环,跳出最近的那个循环
- continue:跳过本次循环,下一次继续
- goto:可以用在任何地方,但是能跨函数使用
fmt.Println("1111111111111")
goto End
fmt.Println("2222222222222")
End:
fmt.Println("3333333333333")
二、函数
函数名:首字母小写是私有的(不能跨包使用),大写是共有的
无参无返回值
package main
import "fmt"
func MyFunc() {
a := 666
fmt.Println("a = ",a)
}
func main(){
MyFunc()
}
有参无返回值
func MyFunc1(b int) {
fmt.Println("b = ",b)
}
func main(){
MyFunc1(777)
不定参数
func Myfunc2(c ...int){
for _,n := range c{
fmt.Println("n = ",n)
}
}
func main(){
Myfunc2(1,2,3,4)
递归调用:一个函数在函数体内调用函数本身
package main
import "fmt"
func Test(n int){
if n > 2{
n--
Test(n)
}
fmt.Println("n = ",n)
}
func main(){
Test(4)
}
func Test(n int){
if n > 2{
n--
Test(n)
}else {
fmt.Println("n = ", n)
}
}
func main(){
Test(4)
}
实例1:
用递归的方式,求出斐波拉契数1,1,2,3,5,8……,给一个整数n,求他的斐波拉契数是多少?
func fbn(n int)int{
if (n == 1)||(n == 2){
return 1
}else{
return fbn(n - 1) + fbn(n - 2)
}
}
func main(){
fmt.Println("fbn(3) = ",fbn(3))
fmt.Println("fbn(4) = ",fbn(4))
fmt.Println("fbn(5) = ",fbn(5))
}
实例2:
编写一个函数sum,可以求出1到多个int的和
func getSum(n int,args... int)int{
sum := n
for i := 0;i < len(args);i++{
sum = sum + args[i]
}
return sum
}
func main(){
res := getSum(5,10,5,10)
fmt.Println("res = ",res)
}
实例3:
请编写一个函数swap(n1 *int,n2 *int)可以交换n1和n2的值
func swap(n1 *int,n2 *int){
t := *n1
*n1 = *n2
*n2 = t
}
func main(){
n1 := 12
n2 := 21
swap(&n1,&n2)
fmt.Printf("n1 = %v ,n2 = %v",n1,n2)
}
注意:
- 函数中的变量是局部的,函数外不能生效
- 基本数据类型和数组默认都是值传递,即进行值拷贝。在函数内修改,不会影响到原来的值
- go语言不支持函数重载(也就的不支持函数同名)
- 在go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量,通过该变量可以对函数调用
func getSum(n1 int,n2 int)int{
return n1 + n2
}
func main(){
a := getSum
fmt.Printf("a的数据类型是%T,getSum的数据类型是%T\n",a,getSum)
res := a(10,40) //等价于getSum(10,40)
fmt.Println("res = ",res)
}
- 函数既然是一种数据类型,因此在go中,函数可以作为形参,并且调用
func myFun(funvar func(int,int)int,num1 int,num2 int )int {
return funvar(num1,num2)
}
func main(){
res := myFun(getSum,50,60)
fmt.Println("res = ",res)
}
- 为了简化数据类型的定义,go支持自定义数据类型
基本语法:type 自定义数据类型名 数据类型 (相当于一个别名)
type myfuntype func(int,int)int
func myFun(funvar myfuntype,num1 int,num2 int )int {
return funvar(num1,num2)
}
func main(){
res := myFun(getSum,500,600)
fmt.Println("res = ",res)
}
- 支持对函数返回值命名
- 使用_标识符,忽略返回值
init函数:通常可以在init函数中完成初始化工作
- 如果一个文件同时包含全局变量定义,init函数和main函数,则执行的流程是变量定义----init函数----main函数
- init函数最主要的作用,就是完成一些初始化的工作
匿名函数
- 在定义匿名函数时直接调用,这种方式匿名函数只能调用一次
//匿名函数
func main(){
res := func(n1 int,n2 int)int {
return n1 + n2
}(10,20)
fmt.Println("res = ",res)
}
- 将匿名函数赋给一个变量(函数变量),再通过该变量来调用匿名函数
func main(){
a := func(n1 int,n2 int)int {
return n1 + n2
}
res := a(11,11)
fmt.Println("res = ",res)
}
全局匿名函数
//定义全局匿名函数
var(
fun = func(n1 int,n2 int) int{
return n1 *n2
}
)
func main(){
res :=fun(4,9)
fmt.Println("res = ",res)
}
闭包
闭包是一个函数和与其相关的引用环境组合的一个整体(实体)
//累加器
func Addupper() func(int)int{
var n int = 10
return func(x int) int {
n = n + x
return n
}
}
func main() {
f := Addupper()
fmt.Println(f(1)) //11
fmt.Println(f(2)) //13
fmt.Println(f(3)) //16
}
- Addupper是一个函数,返回的数据类型是fun(int)int
- 闭包的说明:返回的是一个匿名函数,但是这个匿名函数引用到函数外的n,因此这个匿名函数就和n形成一个整体,构成闭包
- 理解:闭包是类,函数是操作,n是字段,函数和它使用到n构成闭包
- 当我们反复的调用f函数时,因为n是初始化一次,每调用一次就进行累计
- 要搞清楚闭包的关键,就要分析出返回的函数它使用到那些变量,因为函数和它引用到的变量共同构成闭包
实例
编写一个程序,具体要求如下:
(1)编写一个函数 makeSuffix可以接收一个文档后缀名(如.jpg),并返回一个闭包
(2)调用闭包,可以传入一个文件名,如果该文件名没有指定的后缀(比如.jpg),则返回 文件名.jpg,如果已经有.jpg后缀,则返回源文件名
(3)要求使用闭包完成
注:strings.HasSuffix,该函数可以判断某个字符串是否有指定的后缀
func makeSuffix(suffix string) func(string)string{
return func(name string) string {
if ! strings.HasSuffix(name,suffix) {
return name + suffix
}
return name
}
}
func main() {
name :=makeSuffix(".jpg")
fmt.Println(name("aaaaa"))
}
函数中-defer
- 在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时的释放资源,go设计者提供defer(延时机制)
- 在defer将语句放入到栈时,也会将相关的值拷贝同时入栈
func sum(n1 int,n2 int)int {
//当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈(defer栈)
//当函数执行完毕后,再从defer栈,按照先入后出的方式出栈,执行
defer fmt.Println("111",n1)
defer fmt.Println("222",n2)
res := n1 + n2
fmt.Println("333",res)
return res
}
func main() {
res := sum(10,20)
fmt.Println("444",res)
}
- 主要价值:当函数执行完毕后,可以及时的释放函数创建的资源
- 在golang编程中通常做法是,创建资源后,比如(打开了文件,获取了数据库的链接或者是锁资源),可以执行defer file.close() defer connect.close()
- 在defer后,可以继续使用创建资源
- 当函数完毕后,系统会依次从defer栈中取出语句,关闭资源
- 这种机制非常简洁,不用再为什么时候关闭资源而烦心
函数参数的传递方式
- 值传递:值得拷贝(基本数据类型int系列,bool,string,数组和结构体struct)
- 引用传递:地址得拷贝(指针、slice切片、map、管道chan、interface等)
金字塔实例:
func pyramid(totalLevel int) {
for i := 0;i <= totalLevel;i++{
for k := 0;k < totalLevel - i;k++ {
fmt.Print(" ")
}
for j := 1;j <= 2*i-1;j++{
fmt.Print("*")
}
fmt.Println("\n")
}
}
func main(){
var n int
fmt.Println("请输入层数:")
fmt.Scan(&n)
pyramid(n)
}
九九乘法表
func multiply(total int) {
for i := 1;i <= total;i++{
for j := 1;j <= i;j++{
fmt.Printf("%v*%v=%v",j,i,j*i)
fmt.Printf(" ")
}
fmt.Println()
}
}
func main(){
multiply(9)
}