go语言学习笔记3

函数
函数定义说明:
1)func:函数关键字func开始声明
2)FuncName函数名称,根据约定,函数名首字母小写即为private,大写即为public
3)参数列表:函数可以有0个或多个参数,参数格式为:变量名 类型,如果有多个参数通过逗号分隔,不支持默认参数
3)返回类型:变量名不是必须的;如果只有一个返回值且不声明返回值类型,可以省略,包括返回值的括号;如果没有返回值,那么就直接省略最后的返回信息;如果有返回值,那么必须在函数的内部添加return语句
无参无返回值函数的定义

package main
import "fmt"
func fun(){
	fmt.Println("函数运行")
}
func main(){
	//无参无返回值函数的调用:函数名()
	fun()
	}
}

普通参数列表`

package main
import "fmt"
//定义函数时,在函数名后面()定义的参数叫形参
//参数传递,只能由实参传递给形参,不能反过来,单向传递
func MyFunc(a int){
	//a = 111
	fmt.Println("a = ", a)
}
func main(){
	//有参无返回值函数调用:函数名(所需参数)
	//调用函数传递的参数叫实参
	MyFunc(222)
}

同类型多个参数

package main
import "fmt"
func MyFunc(a int, b int){
	fmt.Printf("a = %d, b = %d\n", a, b)
}
func main(){
	MyFunc(111, 222)
}

同类型多个参数简写

func MyFunc(a, b int){
	fmt.Printf("a = %d, b = %d\n", a, b)
}

不同类型多个参数

func MyFunc(a string, b int, c float64){
}

不定参数类型
…int类型这样的类型,…type不定参数类型

package main
import "fmt"
func MyFunc(args ...int){ //传递的实参可以是0个或多个
    fmt.Println("len(args) = ", len(args))//获取用户传递参数的个数
    for i:= 0; i < len(args); i++{
    	fmt.Printf("args(%d) = %d\n", i, args[i])
    }
}
func main(){
	MyFunc()
	MyFunc(1)
	MyFunc(1, 2, 3)
}

迭代,返回2个值,第一个是下标,第二个是下标所对应的数

for i, data := range args{
    	fmt.Printf("args(%d) = %d\n", i, data)
    }

注意:不定参数,一定(只能)放在形参中的最后一个参数
固定参数一定要传参,不定参数根据需求传递

不定参数传递
全部元素

package main
import "fmt"
func MyFunc(tmp ...int){ 
    for _, data := range tmp{
	   fmt.Println("data = ", data)
    }
}
func test(args ...int){
	MyFunc(args...)
}
func main(){
	test(1, 2, 3, 4)
}

只想把后2个参数传递给另外一个函数使用
从args[2]开始(包括本身),把后面所有元素传递过去

func test(args ...int){
	MyFunc(args[2:]...)
}

args[0]~args[2] (不包括数字args[2]),传递过去

func test(args ...int){
	MyFunc(args[:2]...)
}

无参有返回值
一个返回值
有返回值的函数需要通过return中断函数,通过return返回

package main
import "fmt"
func MyFunc() int{ 
    return 111
}
func main(){
	var a int
	a = MyFunc()
	fmt.Println("a = ", a)
	
	b := MyFunc()
	fmt.Println("b = ", b)
}

给返回值起一个变量名,go推荐写法

func MyFunc(result int) { 
    return 111
}
//常用写法
func MyFunc(result int) { 
    result 111
    return 
}

有多个返回值

package main
import "fmt"
func myfunc() (int, int, int) { 
    return 1, 2, 3
}
func main(){
	a, b, c := myfunc()
	fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}

go官方推荐写法

func myfunc() (a, b, c int) { 
    a, b, c = 111, 222, 333
    return 
}

有参有返回值

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
}
func main(){
	max, min := MaxAndMin(10, 20)
	fmt.Printf("max = %d, min = %d\n", max, min)
	
	//通过匿名变量丢弃某个返回值
	a, _ := MaxAndMin(10, 20)
	fmt.Printf("a = %d\n", a)
}

普通函数的调用流程

package main
import "fmt"
func funcc(c int){
	fmt.Println("c = ", c)
}
func funcb(b int){
	funcc(b-1)
	fmt.Println("b = ", b)
}
func funca(a int){
	funcb(a-1)
	fmt.Println("a = ", a)
}
func main(){
	func(3)
	fmt.Println("main")
}

递归调用的流程

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

数字累加
实现1+2+3+…+100的一般写法

package main
import "fmt"
func test()(sum int){
	for i := 1; i <= 100; i++{
		sum += i
	}
	return
}
func main(){
	var sum int
	sum = test()
	fmt.Println("sum = ", sum)
}

用递归实现实现1+2+3+…+100

package main
import "fmt"
func test(i int) int {
	if i == 1{
		return 1
	}
	return i + test(i - 1)
}
func main(){
	var sum int
	sum = test(100)
	fmt.Println("sum = ", sum)
}

函数类型
函数也是一种数据类型,通过type给一个函数类型起名

package main
import "fmt"
func Add(a, b int) int {
	return a + b
}
func Minus(a, b int) int {
	return a - b
}
//FuncType它是一个数据类型
type FuncType func(int, int) int //没有函数名字,没有()
func main(){
	var result int
	result = Add(1, 1) //传统调用方式
	fmt.Println("result = ", result)
	
	//声明一个函数类型的变量,变量名叫fTest
	var fTest FuncType
	fTest = Add            //是变量就可以赋值
	result = fTest(10, 20) //等价于Add(10,20)
	fmt.Println("result2 = ", result)
	
	fTest = Minus
	result = fTest(10, 5) //等价于Minus(10,5)
	fmt.Println("result3 = ", result)
}

回调函数
函数有一个参数是函数类型,这个函数就是回调函数
多态,多种形态,调用同一个接口,不同的表现,可以实现不同表现,加减乘除

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

func main(){
	a := Calc(1, 1, Add)
	fmt.Println("a = ", a)
}

匿名函数和闭包
匿名函数,没有函数名字
闭包就是一个函数“捕获”了和它在同一作用域的其他常量和变量。这就意味着当闭包呗调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量。它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用它,这些变量就还是会存在。

package main
import "fmt"
type FuncType func(int, int)int
func main(){
	a := 10
	str := "mike"
	
	f1 := func(){
		fmt.Println("a = ", a)
		fmt.Println("str = ", str)
	}
	
	f1()
	
	//给一个函数类型起别名
	type FuncType func()//函数没有参数,没有返回值
	var f2 FuncType
	fa = 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
	}(10, 20
	ftm.Printf("x = %d, y = %d\n", x, y)
}

闭包捕获外部变量的特点
闭包以引用方式捕获外部变量

package main
import "fmt"
type 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)
}

闭包的特点

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

变量的的生命周期不由它的作用域决定:squares返回后,变量x仍然隐式的存在于f中

defer(延迟调用,main函数结束前调用)
defer语句只能出现在函数或方法的内部

package main
import "fmt"
func main(){
	defer fmt.Println("BBBBB")
	fmt.Println("AAAAA")
}

AAAAA
BBBBB

多个defer的执行顺序
如果一个函数中有多个defer语句,他们会以LIFO(先进后出)的顺序执行,哪怕函数或某个延迟调用发生错误,这些调用依旧会被执行

package main
import "fmt"
func test(x int) {
	result := 100 / x
	fmt.Println("result = ", result)
}

func main(){
    defer fmt.Println("AAAAA")
	defer fmt.Println("BBBBB")
	//调用一个函数,导致内存出问题
	defer test(0)
	defer fmt.Println("CCCCC")
}

CCCCC
BBBBB
AAAAA

defer和匿名函数结合使用

package main
import "fmt"
func main(){
    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
a = 111, b = 222

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

获取命令行参数

package main
import {
	"fmt"
	"os"  //os.Args所需的包
}
func main(){
	args := os.Args//获取用户输入的所有参数
	//如果用户没有输入,或参数个数不够,则调用该函数提示用户
	if args == nil || len(args) < 2 {
		fmt.Println("err:xxx ip port")
		return
	}
	ip := args[1] //获取输入的第一个参数
	port := args[2] //获取输入的第二个参数
	fmt.Println("ip = %s, port = %s\n", ip, port)
}

局部变量
定义在{}里面的变量是局部变量,只能在{}里面有效
作用域,变量其作用的范围
执行到定义变量那句话,才开始分配空间,离开作用域会自动释放

全局变量
定义在函数外部的变量是全局变量
全局变量在任何地方都能使用

package main
import "fmt"
func test() {
	fmt.Println("test a = ", a)
}
var a int

func main() {
	a = 10
	fmt.Println("a = ", a)
	test()
}


a = 10
test a = 10

不同作用域同名变量
1、不同作用域,允许定义同名变量
2、使用变量的原则,就近原则

package main
import "fmt"

var a byte

func main() {
	var a int
	fmt.Printf("%T\n", a)
}


int
package main
import "fmt"

var a byte

func main() {
	var a int
	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)  //uint8 就是byte
}

工作区
go代码必须放在工作区中。工作区其实就是一个对应于特定工程的目录,它包含3个子目录:src目录、pkg目录、bin目录
src目录:用于以代码包的形式组织并保存go源码文件
若环境变量GOPATH中包含多个工作区的目录路径,像这样执行go install命令就会失效,此时必须设置环境变量GOBIN

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值