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. Cassandra -- Cassandra 3.0版本安装

    ============================================================ 服务器信息 搭建三节点的Cassandra群集: SERVER1: 192.1 ...

  2. Spring Cloud 与 Dubbo、Spring Cloud 与 Docker、Spring Cloud 与 Kubernetes 比较

    出处:http://dockone.io/article/4142

  3. AES 加解密 Java实现

    package com.smt.cipher.symmetry; import java.nio.charset.Charset; import java.security.SecureRandom; ...

  4. LOJ 2743(洛谷 4365) 「九省联考 2018」秘密袭击——整体DP+插值思想

    题目:https://loj.ac/problem/2473 https://www.luogu.org/problemnew/show/P4365 参考:https://blog.csdn.net/ ...

  5. postman测试post请求参数为json类型

    1. 设置Headers Content-Type类型为application/json 2.Body 设置如下.请求的数据类型为Json格式

  6. Go 并发控制--WaitGroup的使用

    开发过程中,经常task之间的同步问题.例如,多个子task并发完成一部分任务,主task等待他们最后结束. 在Go语言,实现同步的一种方式就是WaitGroup. Example package m ...

  7. kafka_2.11-0.8.2.1生产者producer的Java实现

    转载自:http://blog.csdn.net/ch717828/article/details/50818261 1. 开启Kafka Consumer 首先选择集群的一台机器,打开kafka c ...

  8. hadoop 2.7.1安装和配置

    一.安装环境 硬件:虚拟机 操作系统:Centos 6.4 64位 IP:192.168.241.128主机名:admin安装用户:root 二.安装JDK 安装JDK1.7或者以上版本.这里安装jd ...

  9. verilog代码 想法验证---与寄存器输出有关

    verilog代码 想法验证---与寄存器输出有关 1. module test_mind( input wire clk, input wire reset, input wire i, outpu ...

  10. 【转】用python比对数据库表数据的脚本

    最近在做一个数据库异构复制的项目,客户表示需要一个数据比对的工具,我就自己写了一个异构数据库的比对python脚本.这个比对脚本只能比对数量,不能比对具体的记录.使用的sql语句也是最基础的selec ...