通常先执行全局变量后执行init再执行main
如果main.go和引入包中都有变量定义和init函数,那么指行的顺序 是什么???
var 数组名[数组大小]数据类型
var a [5]int
赋初值 a[0]=1
a[1]=30…
二维数组表示一个数组变量中每个元素又是一个一维数组变量,跟java一样
声明二维数组:
var name [n] [m]
// 使用和java一样 n为行 m为列
数组的声明与赋值:
```go
// 1.方式一:完整写法
var arr [3][3]int = [3][3]int{{1,2,3},{4,5,6},{7,8,9},}
// 2.方式二:短变量方式(常用) 注意 这里每行后都要有个逗号
arr := [3][3]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
注意:
golang中的二维数组和java不一样 java不可以直接打印二维数组 但是go可以。
# 1. 普通函数
## 格式:
func 函数名 (参数列表) 返回值 {
函数体
}
在同一个包中(文件夹)函数名是唯一的。
参数列表中的参数为形参,调用函数时填入的参数为实参。
```go
func test(a int,b string) string {
return "傻逼"+b
}
格式:
func 函数名 (args … type) {
}
args — 不定参数名 可自己命名
注:
1. 不定参数必须放在参数列表的最后
2. 普通参数必须传值,不定参数可不传值。
3. 不能将不定参数作为参数传到其他函数中。
func sums(args ...int) int {
count := len(args)
var sum int
for i := 0; i < count; i++ {
sum = sum+args[i]
}
// for _, arg := range args {
// sum = sum+arg
// }
return sum
}
func test(args ...int) {
// 不定参数去传入其他函数中时 需要以下方式
fmt.Println(sums(args[:]...))
fmt.Println(sums(args...))
fmt.Println(sums(args[0],args[1]))
}
// 格式1
func sums(args ...int) int {
sum:=1
return sum
}
// 格式2
func sums(args ...int) (sum int) {
sum=1
return sum
}
// 格式3
func sums(args ...int) (sum int) {
sum=1
return
}
// 格式4 多个返回值
func sums(args ...int) (a,b,sum int) {
sum,a,b=1,1,1
return
}
函数名表示一个地址,是函数在代码区的地址,
func run(s int) string {
return "test"
}
func main() {
fmt.Println(run) // 0x307960
addr := run // 可以通过函数名 去定义其他变量 去指向该地址
fmt.Printf("%T",addr) // 函数类型 func(int) string
}
可以通过类型别名去给 函数类型 起别名。
为什么给函数起别名 参考 面向对象部分
声明函数类型:
var 函数名 函数类型
// 起别名
type demo func(int, int)string
func run(s int,s1 int) string {
return "test"
}
func main() {
// 声明函数类型
var f demo
f =run
fmt.Println(f(1,2)) // test
fmt.Printf("%T",f) // main.demo
}
局部变量
在函数内部定义的变量,仅在当前函数内有效,
全局变量
在函数外部定义的变量,在整个.go文件中都有效
注: 同一个文件夹中的全局变量名不可以重复!
但是全局变量名和局部变量名可以重名 但不推荐!
注:
var sum = 0
func sums(int2 int, int3 int) {
sum = int3+int2
}
func main() {
sum=1
sums(1,2)
fmt.Println(sum) // 3
sum:=1
sums(1,2)
fmt.Println(sum) // 1
}
匿名函数可以直接赋值给一个变量或者直接执行,匿名函数最主要的功能就是实现 了闭包。
func (参数列表) (返回值){
}(实参)
或
f:=func(参数列表) {
}
f(实参)
// 格式1(这里的f接收的是函数执行后返回的值)
func main() {
f:=func(w, e int) int { return 1 } (1,2)
fmt.Printf("%T\n",f) // int
fmt.Println(f)
}
// 格式2 (这里的f接收的是函数本身 需要进行f(参数列表) 去执行该函数)
func main() {
var num = 9
f:=func() {
num++
fmt.Println(num)
}
fmt.Printf("%T\n",f) // 这里的f是个函数类型func() 的变量
f()
fmt.Println(num)
}
匿名函数最主要的功能就是实现了闭包。
https://blog.csdn.net/xiaobinqt/article/details/95110086
https://www.cnblogs.com/xiximayou/p/11882545.html
概念:
闭包,顾名思义,就是一个封闭的包裹,里面包裹着自由变量,就像在类里面定义的属性值一样,自由变量的可见范围随同包裹,哪里可以访问到这个包裹,哪里就可以访问到这个自由变量。
为什么使用闭包:
闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。
这一点与面向对象编程是非常类似的,在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。
type 自定义数据类型名 数据类型 //相当于一个别名
type myInt int
type mySum func(int,int)int //mySum等价于一个函数类型function(int,int)int
例:
ttpe myInt int
var num1 myInt
num1=40
fmt.println("num1"=num1)
1.值传递: 传递的是数值。
2.引用传递;传递的是地址(效率高)。
值传递类型:基本数据类型,数组,结构体。
引用传递:指针,切片slice,map,管道chan,接口interface等
1. 关键字 `defer `用于注册延迟调用。
2. 这些调用直到 `return `前才被执。因此,可以用来做资源清理。
3. 多个`defer`语句,按先进后出的方式执行。
4. `defer`语句中的变量,在`defer`声明时就决定了。
defer就是用来添加函数结束时执行的语句。
即:当前函数结束的时候才会执行defer的语句
1. 关闭文件句柄
2. 锁资源释放
3. 数据库连接释放
关键字 defer ⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行。
注意,defer语句只能出现在函数或方法的内部。
释放资源的defer应该直接跟在请求资源的语句后。
注意:
go 语言的defer功能强大,对于资源管理非常方便,但是如果没用好,也会有陷阱。
defer 是先进后出。
这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法执行了。
执行到defer时系统会将defer后的语句压入到一个独立的栈中,当函数执行完毕后,再从defer栈中按照先入后出的顺序出栈。
func main() {
var whatever [5]int
for i,_ := range whatever {
defer fmt.Println(i)
}
}
//输出:
4
3
2
1
0