Go语言第二阶段学习

Go语言第二阶段学习

文章目录

  • Go语言第二阶段学习
    • 指针:
    • defer:
      • defer的注意事项和细节:
    • 数组:
      • 定义:
      • 数组的命名:
      • 数组的遍历,for-range的使用:
      • 数组的注意事项和细节
      • 二维数组
    • 不定参数:
    • 函数返回值:
    • 函数类型
    • 函数作用域
    • 匿名函数及闭包
      • a. 匿名函数
      • 格式:
      • b. 闭包
    • 函数的注意事项:
    • Go语言支持自定义数据类型:
      • 函数参数的传递方式
      • defer函数(先入后出):
        • defer的特性
        • defer作用

指针:

Go语言第二阶段学习_第1张图片

指针变量存的是一个地址,地址指向的地方才是值*Go语言第二阶段学习_第2张图片
Go语言第二阶段学习_第3张图片

指针变量取的是一个地址,不是一个值。
Go语言第二阶段学习_第4张图片

defer:

defer的注意事项和细节:

Go语言第二阶段学习_第5张图片

通常先执行全局变量后执行init再执行main

如果main.go和引入包中都有变量定义和init函数,那么指行的顺序 是什么???

Go语言第二阶段学习_第6张图片

数组:

定义:

var 数组名[数组大小]数据类型

var a [5]int

赋初值 a[0]=1

​ a[1]=30…

数组的首地址实际上就是第一个元素的地址
Go语言第二阶段学习_第7张图片

数组的命名:

Go语言第二阶段学习_第8张图片

数组的遍历,for-range的使用:

Go语言第二阶段学习_第9张图片

数组的注意事项和细节

  1. 数组是多个相同类型数据的组合,一个数组一旦声明了,其长度是固定的,不能动态变化。
  2. 数组中元素可以是任意的类型,但要是同一类型。
  3. 数组定义后有默认值。 (1)整型和浮点型为0(2)字符串为“ ” (3)布尔型为false
  4. 声明数组就开辟了空间。
  5. go语言中数组是值传递可以进行copy,数组间不会相互影响。
  6. 如果在其他函数中想修改数组可以用指针。
    Go语言第二阶段学习_第10张图片

输出结果为:在这里插入图片描述

二维数组

二维数组表示一个数组变量中每个元素又是一个一维数组变量,跟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
}

函数作用域

  1. 局部变量

    在函数内部定义的变量,仅在当前函数内有效,

  2. 全局变量

    在函数外部定义的变量,在整个.go文件中都有效

    注: 同一个文件夹中的全局变量名不可以重复!
    但是全局变量名和局部变量名可以重名 但不推荐!

注:

  1. 全局变量和局部变量名相同时,就近原则,发挥作用的是局部变量
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
}

匿名函数及闭包

a. 匿名函数

匿名函数可以直接赋值给一个变量或者直接执行,匿名函数最主要的功能就是实现 了闭包。

格式:

​ 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)
}

b. 闭包

匿名函数最主要的功能就是实现了闭包。

https://blog.csdn.net/xiaobinqt/article/details/95110086

https://www.cnblogs.com/xiximayou/p/11882545.html

概念:

闭包,顾名思义,就是一个封闭的包裹,里面包裹着自由变量,就像在类里面定义的属性值一样,自由变量的可见范围随同包裹,哪里可以访问到这个包裹,哪里就可以访问到这个自由变量。

为什么使用闭包:

闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。

这一点与面向对象编程是非常类似的,在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

函数的注意事项:

  1. 函数也是一种数据类型,可以赋给一个变量,该变量是函数的变量,变量可以对函数进行调用。
  2. 函数可以作为形参,并且调用。

Go语言支持自定义数据类型:

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等

defer函数(先入后出):

defer的特性
  1. 关键字 `defer `用于注册延迟调用。
  2. 这些调用直到 `return `前才被执。因此,可以用来做资源清理。
  3. 多个`defer`语句,按先进后出的方式执行。
  4. `defer`语句中的变量,在`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

你可能感兴趣的:(#,Go基础,golang)