遇见go语言的第一天——循环、函数

一、循环

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)
}

注意:

  1. 函数中的变量是局部的,函数外不能生效
  2. 基本数据类型和数组默认都是值传递,即进行值拷贝。在函数内修改,不会影响到原来的值
  3. go语言不支持函数重载(也就的不支持函数同名)
  4. 在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)
}
  1. 函数既然是一种数据类型,因此在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)
}
  1. 为了简化数据类型的定义,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)
}
  1. 支持对函数返回值命名
  2. 使用_标识符,忽略返回值

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

  1. 在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时的释放资源,go设计者提供defer(延时机制)
  2. 在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栈中取出语句,关闭资源
  • 这种机制非常简洁,不用再为什么时候关闭资源而烦心

函数参数的传递方式

  1. 值传递:值得拷贝(基本数据类型int系列,bool,string,数组和结构体struct)
  2. 引用传递:地址得拷贝(指针、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)
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页