Go语言 函数,工程管理

1、无参无返回值函数的使用

package main

import "fmt"

func main() {
	// 无参无返回值函数的调用:函数名()
	func1()
}

// 无参无返回值函数的定义
func func1() {
	str1 := "mysql -uroot -p123456 -S /data/3306/mysql.socket"
	fmt.Println("mysql数据库本地登录命令是#", str1)
}

2、普通参数列表

package main

import "fmt"

// 有参无返回值函数的定义,普通参数列表
// 定义函数时,在函数名后面()定义的参数叫形参
// 参数传递,只能由实参传递传递给形参,不能反过来,单向传递

func func1(a int) {
	fmt.Println("a =", a)
}

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

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

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

func func5(a, b string, c float64, d, e int) {
}

func func6(a string, b string, c float64, d int, e int) {
}

func main() {
	// 有参无返回值函数调用:函数名(所需参数)
	// 调用函数传递的参数叫实参
	func1(666)
	func2(666, 777)
}

3、不定参数类型 args ...type

package main

import "fmt"

func func1(a int, b int) { // 固定参数
	fmt.Printf("a = %d, b = %d\n", a, b)
}

// ...int类型这样的类型,...type不定参数类型
// 注意:不定参数,一定只能放在形参中的最后一个参数
func func2(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])
	}
}

// 返回2个值,第一个是下标,第二个是下标所对应的数
func func3(args ...int) {
	for i, data := range args {
		fmt.Printf("args[%d] = %d\n", i, data)
	}
}

// 固定参数一定要传参,不定参数根据需求传参
func func4(a int, args ...int) {
	fmt.Println("a =", a)
	for i, data := range args {
		fmt.Printf("args[%d] = %d\n", i, data)
	}
}

// 注意:不定参数一定要放在形参中的最后一个参数位置。
// func func5(args ...int, a int) {
// }

func main() {
	func1(666, 777)
	fmt.Println("--------------------------")
	func2(111, 222, 333, 444, 555)
	fmt.Println("--------------------------")
	func3(10, 11, 12, 13, 14, 15)
	fmt.Println("--------------------------")
	func4(9, 10, 11, 12, 13, 14, 15)
	fmt.Println("--------------------------")
	func4(9)
}

4、不定参数传参

package main

import "fmt"

func func1(tmp ...int) {
	for _, data := range tmp {
		fmt.Println("data =", data)
	}
}

func func2(tmp ...int) {
	for _, data := range tmp {
		fmt.Println("data =", data)
	}
}

func test(args ...int) {
	// 全部元素传递给func1
	// func1(args...)

	// 只想把后2个参数传递给两外一个函数使用
	func2(args[:2]...) // args[0]~args[2] 不包括数字args[2],传递过去
	fmt.Println("-----------------")
	func2(args[2:]...) // 从args[2]开始 包括本身,把后面所有元素传递过去
}

func main() {
	test(1, 2, 3, 4)
}

5、一个返回值

package main

import "fmt"

// 无参有返回值:只有一个返回值
// 有返回值的函数需要通过return中断函数,通过return返回
func func1() int {
	return 666
}

// 给返回值起一个变量名,Go推荐写法
func func2() (result int) {
	return 666
}

// 给返回值起一个变量名,Go推荐写法
// 常用写法
func func3() (result int) {
	result = 666
	return result
}

func main() {
	// 无参有返回值函数调用
	var a int
	a = func1()
	fmt.Println("a =", a)

	b := func2()
	fmt.Println("b =", b)

	c := func3()
	fmt.Println("c =", c)
}

6、有多个返回值

package main

import "fmt"

// 有多个返回值
func func1() (int, int, int) {
	return 3306, 3307, 3308
}

// Go官方推荐写法
func func2() (a int, b int, c int) {
	a, b, c = 3306, 3307, 3308
	return
}

func func3() (a, b, c int) {
	a, b, c = 3306, 3307, 3308
	return
}

func main() {
	// 函数调用
	a, b, c := func3()
	fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}

7、有参有返回值

package main

import "fmt"

func func1(a, b int) (max, min int) {
	if a > b {
		max = a
		min = b
	} else {
		max = b
		min = a
	}
	return // 有返回值的函数,必须通过return返回
}

func main() {
	max, min := func1(10, 20)
	fmt.Printf("max = %d, min = %d\n", max, min)
}

8、普通函数的调用流程

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() {
	funca(3) // 调用函数
	fmt.Println("--------------> main")
}

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"

// 实现1加到100
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()
	fmt.Println("sum =", sum)

	sum = test02(100)
	fmt.Println("sum =", sum)

	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
	result = add(1, 1) // 传统调用方式
	fmt.Println("result1 =", 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)
}

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(1, 2, add)
	fmt.Println("a =", a)
}

13、匿名函数和闭包

package main

import "fmt"

func main() {
	a := 10
	name := "zhouwanchun"

	// 匿名函数,没有函数名字,函数定义,还没有调用
	f1 := func() { // 自动推导类型
		fmt.Println("a =", a)
		fmt.Println("name =", name)
	}

	f1()

	fmt.Println("-----------------------------")

	// 给一个函数类型起别名
	type FuncType func() // 函数没有参数,没有返回值
	// 声明变量
	var f2 FuncType
	f2 = f1
	f2()

	fmt.Println("-----------------------------")

	// 定义匿名函数,同时调用
	func() {
		fmt.Printf("a = %d, name = %s\n", a, name)
	}() // 后面的()代表调用此匿名函数

	fmt.Println("-----------------------------")

	// 带参数的匿名函数
	f3 := func(i, j int) {
		fmt.Printf("i = %d, j = %d\n", i, j)
	}
	f3(1, 2)

	fmt.Println("-----------------------------")

	// 定义匿名函数,同时调用
	func(i, j int) {
		fmt.Printf("i = %d, j = %d\n", i, j)
	}(10, 20)

	fmt.Println("-----------------------------")

	// 匿名函数,有参有返回值
	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)

}

14、闭包捕获外部变量的特点

package main

import "fmt"

func main() {
	a := 100
	name := "zhouwanchun"

	fmt.Printf("外部:a = %d, name = %s\n", a, name)

	func() {
		// 闭包以引用方式捕获外部变量
		a = 666
		name = "eric"
		fmt.Printf("内部:a = %d, name = %s\n", a, name)
	}() // ()代表直接调用

	fmt.Printf("外部:a = %d, name = %s\n", a, name)
}

15、闭包的特点

package main

import "fmt"

// 函数的返回值是一个匿名函数,返回一个函数类型
func test01() func() int {
	var x int // 没有初始化,值为0
	return func() int {
		x++
		return x * x
	}
}

func test02() int {
	// 函数被调用时,x才分配空间,才初始化为0
	var x int // 没有初始化,值为0
	x++
	return x * x // 函数调用完毕,x自动释放
}

func main() {
	// 返回值为一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数,f来调用闭包函数。
	// 它不关心这些捕获了的变量和常量是否已经超出了作用域。
	// 所以只有闭包还在使用它,这些变量就还会存在。
	f := test01()
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())

	fmt.Println("--------------------")

	fmt.Println(test02())
	fmt.Println(test02())
	fmt.Println(test02())
	fmt.Println(test02())
	fmt.Println(test02())
	fmt.Println(test02())
	fmt.Println(test02())
}

16、defer的使用

package main

import "fmt"

func main() {
	// defer 延迟调用,main函数结束前调用
	defer fmt.Println("show databases ;")

	fmt.Println("mysql -uroot -p123456 -S /data/3306/mysql.sock")
}

17、多个defer的执行顺序

package main

import "fmt"

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

func main() {
	defer fmt.Println("show databases ;")
	defer fmt.Println("mysql -uroot -p123456 -S /data/3306/mysql.sock")

	// 调用一个函数,导致内存出问题
	defer test(2)
	defer fmt.Println("先执行我")
}

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) // ()代表调用此匿名函数,把参数传递过去,已经先传递参数,只是没有调用

	defer func(a, b int) {
		fmt.Printf("a = %d, b = %d\n", a, b)
	}(30, 40) // ()代表调用此匿名函数,把参数传递过去,已经先传递参数,只是没有调用

	a = 111
	b = 222
	fmt.Printf("外部:a = %d, b = %d\n", a, b)

	c := 10
	d := 20
	defer func() {
		fmt.Printf("c = %d, b = %d\n", c, d)
	}() // ()代表调用此匿名函数

	c = 111
	d = 222
	fmt.Printf("外部:c = %d, d = %d\n", c, d)
}

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 i, data := range list {
		fmt.Printf("list[%d] = %s\n", i, data)
	}

}

// F:\go\day01>go build 1_zhouwanchun.go
// F:\go\day01>1_zhouwanchun.exe a b c
// F:\go\day01>1_zhouwanchun.exe a b c
// n = 4
// list[0] = 1_zhouwanchun.exe
// list[1] = a
// list[2] = b
// list[3] = c
// list[0] = 1_zhouwanchun.exe
// list[1] = a
// list[2] = b
// list[3] = c

20、局部变量

package main

import "fmt"

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

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

	a := 111
	{
		a = 10
		fmt.Println("a = ", a)
	}
	// a = 222

	if flag := 3; flag == 3 {
		fmt.Println("flag = ", flag)
	}

	// flag = 4
}

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() {
	fmt.Printf("a的类型是%T\n", a) // uint8
	var a int                  // 局部变量

	// 不同作用域,允许定义同名变量
	// 使用变量的原则,就近原则
	fmt.Printf("a的类型是%T\n", a) // int

	{
		var a float32
		fmt.Printf("a的类型是%T\n", a) // float32
	}

	test()
}

func test() {
	fmt.Printf("a的类型是%T\n", a) // uint8 就是byte
}

23、导入包

package main

// 忽略此包
import _ "fmt"

func main() {

}

// 给包名起别名
import io "fmt"

func main() {
	io.Println("this is a test.")
}

// .操作
import . "fmt" // 调用函数,无需通过包名
import . "os"

func main() {
	Println("this is a test.")
	Println("os.Args =", Args)
}

// 方式1
import "fmt" // 导入包,必须使用,否则编译不过
import "os"

// 方式2
import (
	"fmt"
	"os"
)

func main() {
	fmt.Println("this is a test.")
	fmt.Println("os.Args =", os.Args)
}

24、Go的工程管理

// 同级目录
1.分文件编程,多个源文件,必须放在src目录
2.设置GOPATH环境变量:为src所在的上一级绝对路径
3.同一个目录,包名必须一样
4.go env查看go相关的环境路径
5.同一个目录,调用别的文件的函数,直接调用即可,无需包名引用
[root@linux-node2 ~]# tree src
src
├── main.go
└── test.go

0 directories, 2 files

src
	main.go
		package main

		func main() {
			test()

		}
	test.go
		package main

		import "fmt"

		func test() {
			fmt.Println("this is a test.")
		}

// 不同目录
1.不同目录,包名就不一样
2.调用不同包里面的函数,格式:包名.函数名()
3.调用别的包的函数,这个包的函数名字如果首字母是小写,无法让别人调用。要想别人能调用,必须首字母大写。
4.只要你导入一个包,Golang就会先执行被导入包的init()函数,然后在执行你的主程序main()函数
执行循序:被导出包的init()函数--->本身初始化init()函数--->main()入口函数
[root@linux-node2 ~]# tree src
src
├── calc
│   └── calc.go
└── main.go

1 directory, 2 files

src
	calc
		calc.go
			package calc

			import "fmt"

			func init() {
				fmt.Println("this is calc init.")
			}

			func Add(a, b int) int {
				return a + b
			}

	main.go
		package main

		import (
			"fmt"
			"calc"
		)

		func init() {
			fmt.Println("this is main init.")
		}

		func main() {
			a := calc.Add(10, 20)
			fmt.Println("a =", a)
		}

原来是go build
src/main.exe 可执行程序

src: 放源代码
如果有多个文件或多个包

1.配置GOPATH环境变量,配置src同级目录的绝对路径
  如:C:\Users\zhouwanchun\Desktop\code\go\src\

2.自动生成bin或pkg目录,需要使用go install命令(了解)
  除了要配置GOPATH=环境变量,还要配置GOBIN=环境变量

src : 放源代码
bin : 放可执行程序
pkg : 放平台相关的库

Go语言 函数,工程管理的更多相关文章

  1. go语言入门(5)工程管理

    在工程中不会简单到只有一个源代码文件,且源文件之间会有相互的依赖关系,早期Go语言使用makefile作为工程管理的临时方案,后来的Go命令行工具的革命性之处在于彻底消除了工程文件的概念,完全用目录结 ...

  2. go语言20小时从入门到精通(六、工程管理)

    在实际的开发工作中,直接调用编译器进行编译和链接的场景是少而又少,因为在工程中不会简单到只有一个源代码文件,且源文件之间会有相互的依赖关系.如果这样一个文件一个文件逐步编译,那不亚于一场灾难. Go语 ...

  3. go语言基础之工程管理和工作区介绍

    1.工程管理 在实际的开发工作中,直接调用编译器进行编译和链接的场景是少而又少,因为在工程中不会简单到只有一个源代码文件,且源文件之间会有相互的依赖关系.如果这样一个文件一个文件逐步编译,那不亚于一场 ...

  4. Golang编程的工程管理

    Golang编程的工程管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.

  5. JVM内存管理------JAVA语言的内存管理概述

    引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...

  6. 使用BLADE构建c++工程管理

    使用BLADE构建c++工程管理 字数764 阅读2753 评论2 喜欢4 一. c++工程依赖管理 之前在百度一直使用comake2构建c++项目,十分方便.免去了手写Makefile的痛苦,很多项 ...

  7. C语言的内存管理

    C语言的内存管理 转载:http://blog.csdn.net/wind19/article/details/5964090   对于一个C语言程序而言,内存空间主要由五个部分组成代码段(.text ...

  8. 动态修改 C 语言函数的实现

    Objective-C 作为基于 Runtime 的语言,它有非常强大的动态特性,可以在运行期间自省.进行方法调剂.为类增加属性.修改消息转发链路,在代码运行期间通过 Runtime 几乎可以修改 O ...

  9. C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针

    C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针 (1)开辟的内存没有释放,造成内存泄露 (2)野指针被使用或释放 (3)非法释放指针 (1)开辟的内存没有释放.造成内存泄露,以下的样 ...

随机推荐

  1. mysql不存在插入否则更新

    1.如果存在就更新,没有就插入,相当于三目运算 CREATE UNIQUE INDEX xxx ON t_msg_user_view(USER_ID); INSERT INTO xxx(user_id ...

  2. 续drone 1.0 新界面调整

    接以前的内容,drone 最新发布的版本又有界面信息的调整了,更方便了. 环境准备 docker-compose 文件 version: '3' services: drone-server: ima ...

  3. APP前端易用性和UI测试

    移动APP使用场景的特点 1.屏幕小: 与Web系统相比,APP安装在手机端,展示屏幕只有几英寸,能够展示的信息就显得非常有限和珍贵,我们需要将有价值的信息放大,放在显眼的位置. 2.场景复杂化: 由 ...

  4. dev 域名与 Chrome

    前几天在相开发时使用什么的样域名比较好呢? 之前使用到 localhost,但只是本地开发,使用 test.com 感觉又不专业. 后来发现了一些指向 127.0.0.1 的域名,比如 localte ...

  5. Distributed processing

    Distributed processing Tool 好处 坏处 类型 支持序列化 支持根据负载动态调度任务 支持c 支持dependency的调度 有成熟的library Actor model ...

  6. vue 下实现 echarts 全国到省份的地图下钻

    vue 下实现 echarts 全国到省份的地图下钻 项目地址:https://github.com/cag2050/vue_echarts_v3_demo

  7. python selenium-webdriver 生成测试报告 (十四)

    测试最后的一个重要的过程就是生成一份完整的测试报告,生成测试报告的主要是通过python的一个第三方模块HTMLTestRunner.py生成,但是生成的测试报告不是特别的美观,而且没有办法统计测试结 ...

  8. Hadoop HDFS的shell(命令行客户端)操作实例

    HDFS的shell(命令行客户端)操作实例 3.2 常用命令参数介绍 -help 功能:输出这个命令参数手册 -ls                  功能:显示目录信息 示例: hadoop fs ...

  9. Linux平台下停止后台进程脚本编写

    1.场景说明 [root@master ~]# jps -m 33050 Jps -m 3299 NameNode 3747 ResourceManager 9028 ConsoleConsumer  ...

  10. xcode 添加target