Day_02
1.无参数无返回值函数的使用
package main import "fmt" //无参无返回值函数的定义 func MyFunc() { a := 666 fmt.Println("a= ", a) } func main() { //无参无返回值函数的调用,函数名() MyFunc() }
2.普通参数列表
package main import "fmt" //有参无返回值函数的定义,普通参数列表 func MyFunc01(a int) { //a = 111 fmt.Println("a = ", a) } //传递多个参数 func MyFunc02(a int, b int) { fmt.Printf("a = %d,b = %d\n", a, b) } func MyFunc03(a, b int) { fmt.Printf("a = %d,b = %d\n", a, b) } func MyFunc04(a int, b string, c float64) { } func MyFunc05(a, b string, c float64, d, e int) { } func main() { MyFunc01(666) MyFunc02(123, 456) MyFunc03(888, 999) }
3.不定参数类型
package main import "fmt" //...int类型这样的类型,...type不定参数类型 //不定参数一定只能放在形参中的最后一个参数 func MyFunc01(args ...int) { //传递的参数可以是0个或多个 fmt.Printf("传递了%d个参数\n", len(args)) //获取用户传递参数的数量 //不定参数数量返回的是一个列表,所以我们可以用for循环将获取其值 for i := 0; i < len(args); i++ { fmt.Printf("args[%d] = %d\n", i, args[i]) } fmt.Println("========================================") //也可以用这种方式,返回2个值,第一个是下标,第二个是下标所对应的数 for i, data := range args { fmt.Printf("第二种方式:args[%d] = %d\n", i, data) } } func main() { MyFunc01() fmt.Println("++++++++++++++++++++++++++++++++++") MyFunc01(1) fmt.Println("++++++++++++++++++++++++++++++++++") MyFunc01(1, 2, 3) }
4.不定参数传递
package main import "fmt" func myfunc(tmp ...int) { for _, data := range tmp { fmt.Println("data = ", data) } fmt.Println("我是myfunc+++++++++") } func myfunc2(tmp ...int) { for _, data := range tmp { fmt.Println("data = ", data) } fmt.Println("我是myfunc2+++++++++") } func test(args ...int) { //全部元素传递给myfunc myfunc(args...) //只想把后2个参数传递给另外一个函数使用 //myfunc2(args[:2]...) //从args[0]~args[2](不包括args[2]),传递过去 myfunc2(args[2:]...) //从args[2]开始(包括本身),把后面所有元素传递过去 } func main() { test(1, 2, 3, 4) }
5.一个返回值
package main import "fmt" //无参有返回值;只有一个返回值 //有返回值的函数需要通过return中断函数,通过return返回 func myfunc01() int { return 666 } //给返回值起一个变量名,go推荐写法,也是常用写法 func myfunc02() (result int) { result = 777 return } func main() { //无参有返回值函数调用,定义一个变量接收返回值 var a = myfunc01() fmt.Println("a", a) b := myfunc01() fmt.Println("b= ", b) c := myfunc02() fmt.Println("c= ", c) }
6.多个返回值
package main import "fmt" //多个返回值 func myfunc01() (int, int, int) { return 1, 2, 3 } //Go官方推荐写法 func myfunc02() (a int, b int, c int) { a, b, c = 111, 222, 333 return } func myfunc03() (a, b, c int) { a, b, c = 444, 555, 666 return } func main() { //函数调用 a, b, c := myfunc03() fmt.Printf("a = %d,b = %d,c = %d\n", a, b, c) }
7.有参数有返回值
package main import "fmt" //函数定义 func MaxAndMin(a, b int) (max, min int) { if a > b { max = a min = b } else { max = b min = a } return //有返回值的函数,必须通过return返回 } func main() { max, min := MaxAndMin(50, 10) fmt.Printf("最大值是:%d,最小值是:%d\n", max, min) //通过匿名变量丢弃某个返回值 i, _ := MaxAndMin(50, 10) fmt.Printf("i = %d", i) }
8.普通函数的调用流程
package main import "fmt" func funcb() (b int) { b = 222 fmt.Println("funcb b = ", b) return } func funca() (a int) { a = 111 b := funcb() fmt.Println("funca b = ", b) //调用另一个函数 fmt.Println("funca a = ", a) return //返回 } func main() { fmt.Println("main func") a := funca() fmt.Println("main a = ", a) }
9.函数递归的调用流程
package main import "fmt" func test(a int) { if a == 1 { //函数终止调用的条件,非常重要 fmt.Println("a = ", a) return //终止函数调用 } //函数调用自身 test(a - 1) fmt.Println("a = ", a) } func main() { test(3) fmt.Println("main") }
10.通过递归实现的累加
package main import "fmt" //普通方式实现累加 func test01() (sum int) { for i := 1; i <= 100; i++ { sum += i } return } //递归方式实现累加(递减) func test02(i int) int { if i == 1 { return 1 } return i + test02(i-1) } //递归方式实现累加(递增) func test03(i int) int { if i == 100 { return 100 } return i + test03(i+1) } func main() { var sum int //sum = test01() //sum = test02(100) sum = test03(1) fmt.Println("sum = ", sum) }
11.函数类型
package main import "fmt" func Add(a, b int) int { return a + b } func Minus(a, b int) int { return a - b } //函数也是一种数据类型,通过type给一个函数类型起名 //FuncType它是一种函数类型 type FuncType func(int, int) int //没有函数名字,没有{} func main() { var result int result1 = Add(5, 1) //传统调用方式 fmt.Println("result1 = ", result1) //声明一个函数类型的变量,变量名叫fTest var fTest FuncType fTest = Add //是变量就可以赋值 result2 = fTest(10, 20) //等价于Add(10,20) fmt.Println("result2 = ", result2) }
12.回调函数
package main import "fmt" type FuncType func(int, int) int //实现加法 func Add(a, b int) int { return a + b } //实现减法 func Minus(a, b int) int { return a - b } //实现乘法 func Mul(a, b int) int { return a * b } //回调函数,函数有一个参数是函数类型,这个函数就是回调函数 //计算器,可以进行四则运算 //多态,多种形态,调用同一个借口,不同的表现,可以实现不同的功能,加减乘除 //先有想法,后面再实现功能,这就是回调函数的意义 func Calc(a, b int, fTest FuncType) (result int) { fmt.Println("Calc") result = fTest(a, b) //这个函数还没有实现 //result = Add(a, b) //Add()必须先定义,才能调用 return } func main() { a := Calc(10, 5, Mul) //那么在这里我想实现减法,我在上面定义一下,然后拿到这里修改一下Add为Minus就可以了,类似的乘法,除法同理,有利于程序的扩展 fmt.Println("a = ", a) }
13.匿名函数和闭包
package main import "fmt" func main() { a := 10 str := "Mike" //匿名函数,没有函数名字,函数定义,暂时还没有调用 f1 := func() { //自动推导类型 fmt.Println("a = ", a) fmt.Println("str = ", str) } f1() //给一个函数类型起别名 type FuncType func() //函数没有参数,没有返回值 //声明变量 var f2 FuncType f2 = f1 f2() //定义匿名函数,同时调用 func() { fmt.Printf("a = %d,str = %s\n", a, str) }() //后面的括号代表调用此匿名函数 //带参数的匿名函数 f3 := func(i, j int) { fmt.Printf("i = %d,j = %d\n", i, j) } f3(1, 2) //定义匿名函数,同时调用 func(i, j int) { fmt.Printf("i = %d,j = %d\n", i, j) }(10, 20) //匿名函数,有参数有返回值 x, y := func(i, j int) (max, min int) { if i > j { max = i min = j } else { max = j min = i } return }(50, 20) fmt.Printf("x = %d,y = %d\n", x, y) }
14.闭包捕获外部变量的特点
package main import "fmt" func main() { a := 10 str := "Mike" func() { //闭包以引用方式捕获外部变量 a = 666 str = "go" fmt.Printf("内部:a = %d,str = %s\n", a, str) }() //()代表直接调用 fmt.Printf("外部:a = %d,str = %s\n", a, str) } /* 打印结果: 内部:a = 666,str = go 外部:a = 666,str = go */
15.闭包的特点
package main import "fmt" //函数的返回值是一个匿名函数,返回一个函数类型 func test02() func() int { var x int //没有初始化,值为0 return func() int { x++ return x * x } } func main() { //返回值为一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数,f来调用闭包函数 //它不关心这些捕获了的变量和常量是否已经超出了作用域 //所以只有闭包还在使用它,这些变量就还会存在。 f := test02() fmt.Println(f) //1 fmt.Println(f) //4 fmt.Println(f) //9 fmt.Println(f) //16 fmt.Println(f) //25 } func test01() int { //函数被调用时,x才分配空间,才初始化为0 var x int //没有初始化,值为0 x++ return x * x //函数调用完毕,x自动释放 } func main01() { fmt.Println(test01()) fmt.Println(test01()) fmt.Println(test01()) fmt.Println(test01()) }
16.defer的使用
package main import "fmt" /* 关键字defer用于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行, defer语句只能出现在函数或方法的内部。 */ func main() { //defer延迟调用 在函数结束前调用,所以可以看到aaaaaaaa先打印 defer fmt.Println("bbbbbbbbbbbbbbbbbbbb") fmt.Println("aaaaaaaaaaaaaaaaaaaa") } /* 运行结果: aaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbb */
17.多个defer的执行顺序
package main import "fmt" /* 如果一个函数中有多个defer语句,他们会以为LIFO(后进先出)的顺序执行,哪怕函数或某个延迟调用发生错误,这些调用依旧会被执行。 */ func test(x int) { result := 100 / x fmt.Println("result = ", result) } func main() { defer fmt.Println("aaaaaaaaaaaaaaaaaaaa") defer fmt.Println("bbbbbbbbbbbbbbbbbbbb") //调用一个函数,导致内存出问题,故意让除以0 defer test(0) defer fmt.Println("ccccccccccccccccc") } /* 运行结果: ccccccccccccccccc bbbbbbbbbbbbbbbbbbbb aaaaaaaaaaaaaaaaaaaa panic: runtime error: integer divide by zero goroutine 1 [running]: main.test(0x0) D:/Let's Go/17_多个defer的执行顺序.go:6 +0xd9 main.main() D:/Let's Go/17_多个defer的执行顺序.go:18 +0x15e exit status 2 */
18.defer和匿名函数结合使用
package main import "fmt" func main() { a := 10 b := 20 defer func(a, b int) { fmt.Printf("a = %d,b = %d\n", a, b) }(a, b) //代表调用此匿名函数,把参数传递过去,已经先传递参数,只是没有调用 a = 111 b = 222 fmt.Printf("外部:a = %d,b = %d\n", a, b) //输出结果为先打印外部: a=111,b=222之后打印的是a = 10,b = 20 } func main01() { a := 10 b := 20 defer func() { fmt.Printf("a = %d,b = %d\n", a, b) }() //代表调用此匿名函数 a = 111 b = 222 fmt.Printf("外部:a = %d,b = %d\n", a, b) //输出结果为两个打印都为a = 111,b = 222 }
19.获取命令行参数
package main import "fmt" import "os" func main() { //接收用户传递的参数,都是以字符串方式传递到一个列表里面 list := os.Args n := len(list) fmt.Println("n = ", n) //xxx.exe a b for i := 0; i < n; i++ { fmt.Printf("list[%d] = %s\n", i, list[i]) } //第二种方式 for _, data := range list { fmt.Printf(" %s\n", data) } }
20.局部变量
package main import "fmt" func test() { a := 10 fmt.Println("a = ", a) } func main() { //定义在{}里面的变量就是局部变量,只能在{}里面有效 //执行到定义变量那句话,才开始分配空间,离开作用域 //作用域,变量起作用的范围 { i := 10 fmt.Println("i = ", i) } if flag := 3; flag == 3 { fmt.Println("flag = ", flag) } }
21.全局变量
package main import "fmt" func test() { fmt.Println("test a = ", a) } //定义在函数外部的变量是全局变量,全局变量在任何地方都能使用 var a int func main() { a = 10 fmt.Println("a = ", a) test() }
22.不同作用域同名变量
package main import "fmt" var a byte //全局变量 func main() { var a int //局部变量 //1.不同作用域,允许定义同名变量 //2.使用变量的原则,就近原则 fmt.Printf("%T\n", a) //int { var a float32 fmt.Printf("2: %T\n", a) //float32 } test() } func test() { fmt.Printf("3: %T\n", a) //unit8 就是byte类型 }
23.工作区
Go代码必须放在工作区中。工作区其实就是一个对应于特定工程的目录,它应包含3个子目录:src目录、pkg目录和bin目录。 src目录:用于以代码包的形式组织并保存Go源码文件。(比如:.go .c .h 等等) pkg目录:用于存放经由go install命令构建安装后的代码包(包含Go库源码文件)的 ".a"归档文件。 bin目录:与pkg目录类似,在通过go install命令完成安装后,保存由Go命令源码文件生成的可执行文件。 目录src用于包含所有的源代码,是Go命令行工具一个强制的规则,而pkg和bin则无需手动创建,如果必要Go命令行工具在构建过程中会自动创建这些目录。 需要特别注意的是,只有当环境变量GOPATH中只包含一个工作区的目录路径时,go install命令才会把命令源码安装到当前工作区的bin目录下。 若环境变量GOPATH中包含多个工作区的目录路径,像这样执行go install命令就会失败,此时必须设置环境变量GOBIN。 GOPATH设置 为了能够构建这个工程,需要先把所需工程的根目录加入到环境变量GOPATH中。否则,即使处于同一工作目录(工作区),代码之间也无法通过绝对代码包路径完成调用。
24.导入包的常用方式
package main /* //方式1 import "fmt" import "os" //方式2 常用 import ( "fmt" "os" ) //方式3 .操作 import . "fmt" //调用函数,无需通过包名 import . "os" //方式4 给包起别名 import io "fmt" func main() { io.Println("这是别名方式导入包") } //忽略此包 import _ "fmt" //该操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数 func main() { fmt.Println("this is a test") fmt.Println("os.Args = ", os.Args) fmt.Println("this is a test") } */
25.工程管理
同级目录: 1、分文件编程(多个源文件),必须放在src目录 2、设置GOPATH环境变量 3、同一个目录,包名必须一样 4、go env查看go相关的环境路径 5、同一个目录,调用别的文件的函数,直接调用即可,无需包名引用 不同级目录: 1、不同目录,包名不一样 2、调用不同包里面的函数,格式:包名:函数名() 3、调用别的包的函数,这个包函数名字如果是小写,无法让别人调用,要想别人调用,必须首字母大写