go语言基本语法:函数、工程管理

一、函数

(一)无参无返回值函数

//无参无返回值函数的定义
func MyFunc() {
	a := 666
	fmt.Println("a=", a)
}
func main() {
	//无参无返回值函数的调用:函数名()
	MyFunc()
}

(二)普通参数列表

//有参无返回值函数的定义,普通参数列表
//定义函数时,在函数名后面()定义的参数叫形参
//参数传递,只能由实参传递给形参,不能反过来,单向传递
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 int, b string, c float64) {
	fmt.Printf("a=%d,b=%s, c=%f\n", a, b, c)
}
func main() {
	//有参无返回值函数调用:函数名(所需参数)
	//调用函数传递的参数叫实参
	MyFunc01(666)
	MyFunc02(666, 777)
	MyFunc03(666, "abc", 4.14)
}

(三)不定参数类型

//注意:不定参数,一定(只能)放在形参中的最后一个参数
func MyFunc02(args ...int) { //...int类型这样的类型,...type不定参数类型
	fmt.Println("len(args)=", len(args)) //获取用户传递参数的个数
	for i := 0; i < len(args); i++ {
		fmt.Printf("args[%d]=%d\n", i, args[i])
	}
	//返回2个值,第一个是下标,第二个是下标所对应的数
	for i, data := range args {
		fmt.Printf("args[%d]=%d\n", i, data)
	}
}
//固定参数一定要传参,不定参数根据需求传参,不定参数放最后
func MyFunc03(a int, args ...int) {

}
func main() {
    MyFunc02(1)
	MyFunc02(1, 2, 3)
	MyFunc03(111, 1, 2, 3)
}

(四)不定参数传递

func myfunc02(tmp ...int) {
	for _, data := range tmp {
		fmt.Println("data=", data)
	}
}
func test(args ...int) {
	//全部元素传递给mufunc01
	myfunc02(args...)
	myfunc02(args[:2]...) //从args[2]开始(不包括本身),把前面所有元素传递过去
	myfunc02(args[2:]...) //从args[2]开始(包括本身),把后面所有元素传递过去
}
func main() {
	test(1, 2, 3, 4)
}

(五)一个返回值函数

//无参,有返回值,只有一个返回值
//有返回值的函数,需要通过return来中断函数,返回
func myfunc01() int {
	return 666
}
//给返回值起一个变量名,go语言推荐写法
func myfunc02() (result int) {
	result = 666
	return
}
func myfunc03() (result int) {
	return 666
func main() {
	var a int
	a = myfunc01()
	fmt.Println("a=", a)
	b := myfunc01()
	fmt.Println("b=", b)
	c := myfunc02()
	fmt.Println("c=", c)
}

(六)多个返回值

//多个返回值
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 = 111, 222, 333
	return
}
func main() {
	a, b, c := myfunc02()
	fmt.Printf("a=%d,b=%d,c=%d\n", a, b, c)
}

(七)有参有返回值函数

func MaxAndMin(a, b int) (max, min int) {
	if a > b {
		max = a
		min = b
	} else {
		min = a
		max = b
	}
	return
}
func main() {
	max, min := MaxAndMin(10, 20)
	fmt.Printf("max=%d,min=%d\n", max, min)
	m, _ := MaxAndMin(10, 20) //匿名函数丢弃某个返回值
	fmt.Printf("max=%d\n", m)
}

(八)函数调用流程

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.Printf("main a=%d\n", a)
}
//函数调用流程:先调用后返回,先进后出
//函数递归,函数调用自己本身,利用此特点

(九)函数递归调用流程

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
func test01() (sum int) {//非递归
	for i := 1; i <= 100; i++ {
		sum += i
	}
	return
}
func test02(i int) int {//1+2+...+100
	if i == 1 {
		return 1
	}
	return i + test02(i-1)
}
func test03(i int) int {//100+99+...+1
	if i == 100 {
		return 100
	}
	return i + test03(i+1)
}
func main() {
	var sum int
	sum = test01()
	fmt.Println("sum=", sum)
	sum = test02(100)
	fmt.Println("sum=", sum)
	sum = test03(1)
	fmt.Println("sum=", sum)
}

(十)函数类型

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
	result = Add(1, 1)
	fmt.Println("result=", result)
	var fTest FuncType//声明一个函数类型的变量,变量名叫fTest
	fTest = Add            //是变量就可以赋值
	result = fTest(10, 20) //等价于Add(10,20)
	fmt.Println("result=", result)
	fTest = minus
	result = fTest(10, 5)
	fmt.Println("result=", result)
}

(十一)回调函数

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 Div(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)
	a = Calc(1, 1, Minus)
	fmt.Println("a=", a)
}

(十二)匿名函数与闭包

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("a=%d,b=%d\n", i, j)
}
f3(1, 2)
func(i, j int) {//定义匿名函数,同时调用
	fmt.Printf("a=%d,b=%d\n", i, j)
}(3, 4)
x, y := func(i, j int) (max, min int) {//匿名函数,有参有返回值
	if i > j {
		max = i
		min = j
	} else {
		max = j
		min = i
	}
	return
}(10, 20)
fmt.Printf("x=%d,y=%d\n", x, y)

(十三)闭包捕获外部变量的特点

a := 10
str := "mike"
func() {//闭包以引用的方式捕获变量	
	a = 666
	str = "go"
	fmt.Printf("inner a=%d,str=%s\n", a, str)
}() //()代表直接调用
fmt.Printf("outer a=%d,str=%s\n", a, str)

(十四)闭包的特点

func test01() int {
	//函数被调用时,x才分配空间,才初始化为0
	var x int //没有初始化,值为0
	x++
	return x * x //函数调用完毕,x自动释放
}
//函数的返回值是一个匿名函数,返回一个函数类型
func test02() func() int {
	var x int
	return func() int {
		x++
		return x * x
	}
}
func main() {
    fmt.Println(test01())
	fmt.Println(test01())
	//返回值为一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数,f来调用闭包函数
	//它不关心这些捕获了的变量和常量是否已经超出了作用域
	//所以只有闭包还在使用它,这些变量就会存在
	f := test02()
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
}

(十五)defer的使用

//defer延迟调用,main结束前调用
defer fmt.Println("bbbbbbbbbbbbbb")
fmt.Println("aaaaaaaaaaaaaa")

(十六)多个defer的执行顺序

func test(x int) {
	result := 100 / x
	fmt.Println(result)
}
func main() {
	//如果一个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行,
	//哪怕函数或某个延迟返回发生错误,这些调用依旧会被执行
	defer fmt.Println("aaaaaaaaaaaaaa")
	defer fmt.Println("bbbbbbbbbbbbbbbbbb")
	//调用一个函数导致内存出问题
	defer test(0)
	defer fmt.Println("cccccccccccccccccccc")
}

(十七)defer和匿名函数的结合使用

a := 10
b := 20
defer func() {
	fmt.Printf("a=%d,b=%d\n", a, b)
}() //()代表调用此匿名函数
defer func(a, b int) {
	fmt.Printf("a=%d,b=%d\n", a, b)
}(a, b) //()代表调用此匿名函数,把参数传递过去,已经先传递参数,只是因为defer而没有调用
defer func(a, b int) {
	fmt.Printf("a=%d,b=%d\n", a, b)
}(1, 2)
a = 111
b = 222
fmt.Printf("外部:a=%d,b=%d\n", a, b)

(十八)获取命令行参数

list := os.Args//接受用户传递的参数,都是以字符串方式传递的
n := len(list)
fmt.Println("n=", n)
for i := 0; i < n; i++ {
	fmt.Printf("list[%d]=%s\n", i, list[i])
}
for i, data := range list {
	fmt.Printf("list[%d]=%s\n", i, data)
}//要导入os包

(十九)局部变量

//定义在{}里面的变量就是局部变量,只能在{}里面有效
//执行到定义变量那句话的手,才开始分配空间,离开作用域会自动释放
//作用域,变量起作用的范围
//a = 111
{
	i := 10
	fmt.Println("i=", i)
}
//i = 111
if flag := 3; flag == 3 { //flag离开这个if语句就不存在了
	fmt.Println("flag=", flag)
}
flag = 4

(二十)全局变量

//定义在函数外面的变量是全局变量
//全局变量在任何地方都能使用
var a int
func test() {
	fmt.Println("a=", a)
}
func main() {
	a = 10
	fmt.Println("a=", a)
	test()
}

(二一)不同作用域同名变量

var a byte //全局变量
func main() {
	var a int //局部变量
	//1.不同作用域允许定义同名变量
	//2.使用变量的原则,就近原则
	fmt.Printf("1:%T\n", a)
	{
		var a float32
		fmt.Printf("2:%T\n", a)
	}
	test()
}
func test() {
	fmt.Printf("3:%T\n", a)
}

(二二)导入包

/*//方式一
//import "fmt" //导入包必须使用
//import "os"

//方式二
import (
	"fmt"
	"os"
)
func main() {
	fmt.Println("testetst")
	fmt.Println("os.Args=", os.Args)
}*/

//.操作,不推荐
/*import . "fmt"//调用函数无需通过包名
func main() {
	Println("testetst")
}*/
//给包起别名
/*import io "fmt"
func main() {
	io.Println("trstteste")
}*/

//忽略此包
import _ "fmt"
func main() {
	fmt.Println("trstteste")
}

二、工程管理

(一)说明

1.分文件编程(多个源文件),必须放在src目录

2.设置GOPATH环境变量

3.同一个目录,包名必须一样

4.go env 查看go相关的环境路径

5.同一个目录,调用别的文件的函数,直接调用即可,无需包名引用

6.不同目录,包名不同

7.调用不同包里面的函数,格式:包名.函数名()

8.如果调用别的包的函数,这个包函数名字如果是小写,无法让别人调用,要想别人能调用,必须首字母大写

(二)总结

1.src:放源代码

如果有多个文件或多个包

1)配置GOPATH环境变量,如:D:\software\go\code\day02\25_工程管理(配置src同级目录的绝对路径)

2)如果想要自动生成bin和pkg目录,需要使用 go install命令,除了要配置GOPATH环境变量还要配置GOBIN环境变量

2.bin:放可执行程序

3.pkg:放平台相关的库

猜你喜欢

转载自blog.csdn.net/u014596135/article/details/82872071