1.不定参数类型
func MyFun01(a int, b int){
//a = 111
fmt.Println("a =", a,b)
}
//...type不定参数类型
func MyFunc02(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])
}
fmt.Println("===================")
//range返回2个值,第一个是下标,第二个是下标对应的数据
for i,data := range args{
fmt.Printf("args[%d] = %d\n", i, data)
}
}
func main() {
MyFunc02()
fmt.Println("+++++++++++++++++")
MyFunc02(1)
fmt.Println("+++++++++++++++++")
MyFunc02(1,2,3)
}
2.不定参数的传递
func myfunc(tmp ...int){
for _,data := range tmp{
fmt.Println("data =", data)
}
}
func myfunc2(tmp ...int){
for _,data := range tmp{
fmt.Println("data =", data)
}
}
func test(args ...int){
//全部元素传递给myfunc
//myfunc(args...)
//只想把后2个参数传递给另外一个函数使用
//myfunc2(args[0:2]...) //从0到2(不包括2)传递过去
myfunc2(args[2:]...) //从args[2]开始(包括本身),把后面所有元素传递过去
}
func main() {
test(1, 2, 3)
}
3.单返回值常用写法
func myfunc01() int{
return 666
}
//给返回值起一个变量名,go推荐写法
//常用写法
func myfunc02() (result int) {
result = 666
return
}
func main() {
//无参返回值函数调用
var a int
a = myfunc01()
fmt.Println("a =", a)
//自动推导类型
b := myfunc02()
fmt.Println("b =", b)
}
4.多个返回值
//多个返回值
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 := myfunc03()
fmt.Println(a, b, c)
}
求最大最小值
//函数名小写私有,大写公有
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.Println(max, min)
}
5.递归(斐波那且数列,汉诺塔)
;i<=100;i++{
sum+=i
}
return
}
func test02(i int) int {
if i==1{
return 1
}
return i + test02(i-1)
}
func main() {
//test(3)
var sum int
sum = test02(100)
fmt.Println(sum)
}
函数多态,定义函数变量
func Add(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)
//声明一个函数类型的变量
var fTest FuncType
fTest = Add //是变量就可以赋值
result = fTest(10, 20)
fmt.Println(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 Calc(a, b int, fTest FuncType) (result int){
fmt.Println("Calc")
//result = Add(a, b) //Add这个函数必须先定义后,才能调用
result = fTest(a, b) //这个函数还没有实现
return
}
func main() {
a := Calc(1, 1, Add)
fmt.Println(a)
b := Calc(1, 1, minus)
fmt.Println(b)
}
4.闭包
所谓闭包就是一个函数"捕获"了和它在同一作用域的其他常量和变量,这就意味着当闭包被调用的时候,不管程序在什么地方调用,闭包都能使用这些常量或者变量。它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用它,这些变量就还会存在。
匿名函数基本语法
func main() {
a := 10
str := "mike"
//匿名函数,没有函数名字
f1 := func() { //:=自动推导类型,常用
fmt.Println(a,str)
}
f1()
//给定一个函数类型起别名
type FuncType func() //函数没有参数,每有返回值
//声明变量
var f2 FuncType
f2 = f1
f2()
//定义匿名函数,同时调用
func() {
fmt.Printf("a =%d, str =%\n", a, str)
}() //后面的()代表给匿名函数传参,调用此匿名函数
//带参数的匿名函数
f3 := func(i, j int){
fmt.Println(i, j)
}
f3(1, 2)
//定义时同时调用
func(i, j int){
fmt.Println(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)
fmt.Println(x,y)
}
在匿名函数内修改外部变量仍同步修改,闭包以引用方式捕获外部变量
//闭包捕获外部变量的特点
func main() {
a := 10
str := "mike"
func(){ //在匿名函数内修改外部变量仍同步修改
//闭包以引用方式捕获外部变量
a = 666
str = "gogogo"
fmt.Println(a, str)
}()
fmt.Println(a, str)
}
变量的生命周期不是由闭包的作用域决定,它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用它,这些变量就还会存在。
func test01() int {
//函数被调用时,x才分配空间,才初始化为0
var x int
x++
return x*x //函数调用完毕,x自动释放
}
//函数的返回值是一个匿名函数,返回一个类型
func test02() func() int{
var x int //没有初始化,值为0
return func() int{
x++
return x*x
}
}
func main() {
//fmt.Println(test01())
//fmt.Println(test01())
//fmt.Println(test01())
//fmt.Println(test01())
//返回值为一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数
//变量的生命周期不是由闭包的作用域决定
f := test02()
fmt.Println(f()) //1
fmt.Println(f()) //4
fmt.Println(f()) //9
fmt.Println(f()) //16
}
获取命令行参数
package main
import (
"fmt"
"os"
)
func main() {
//接收用户传递的参数,是以字符串方式传递
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)
}
}
全局变量:定义在函数外部的变量是全局变量
局部变量:定义在{}里面的变量就是局部变量,只能在大括号内有效。执行到定义变量那句话,才开始分配空间,离开作用域自动释放
不同作用域允许定义同名变量,遵循就近原则
5.工作区
go代码必须放在工作区中,工作区其实就是一个对英语特定工程的目录
它包含三个子目录:src目录、pkg目录和bin目录
-
src目录:用于以代码包的形式组织并保存Go源码文件(比如:.go、.c、.h)。分文件编程(多个源文件),必须放在src目录。
1)如果有多个文件或多个包,配置src同级目录的绝对路径。
2)如果要自动生成pkg、bin目录。需要使用go install命令。除了要配置GOPATH环境变量,还要配置GOBIN环境变量 -
pkg目录:用于存放经由gp install命令构建安装后的代码包(包含go库源码文件)的".a"归档文件
-
bin目录:与pkg目录类似,在通过go install命令完成安装后,保存由go命令源码生成的可执行文件
分文件编程:
同级目录:
- 同一个目录,包名必须一样
- 同一个目录,调用别的文件的函数,直接调用即可,无需包名引用
不同级目录:
- 不同目录,包名不一样
- 调用不同包里面的函数,格式:包名.函数名()
- 调用别的包的函数,这个包函数名字如果是小写,无法让别人调用;要想别人能调用,必须首字母大写
main函数和init函数执行流程:
先执行导入包中的函数,再执行init(),最后执行main()。但有时用户可能需要导入一个包,但是不需要引用这个包的标识符,在这种情况,可使用空白标识符_来重命名这个导入:
import _ "fmt"