golang基础知识整理

1、声明map
//第一种方式
var m1 map[string]string
m1 = make(map[string]string)
m1["a"] = "aa"
m1["b"] = "bb"

//第二种方式
m2 := make(map[string][string])
m2["c"] = "cc"

//第三种方式
m3 := map[string]string{
  "a": "aa",
  "b": "bb",
}

//查找键值是否存在
if v, ok := map["a"];ok{
  
}
2、声明数组
//方式一
var arr [2]int
arr[0]=1
arr[1]=2

//方式二
var arr = [2]int{1,2}
//or
arr := [2]int{1,2}

//方式三
var arr = [...]int{1,2}
//or
arr := [...]int{1,2}

//方式四
var arr = [...]int{1:1,0:2}
//or
arr := [...]int{1:1,0:2}

//创建数组切片
var array3 = []int{9, 10, 11, 12}

//声明一个int型的切片,声明切片和声明数组类似,但是不指定长度
var a []int

//使用make声明长度和容量的切片
b := make([]int, 5, 6)

//切片使用的注意事项
当slice中有两个冒号时,即slice[start:index:max],它的容量就是(max - start),实际引用的数组时从数组start索引开始到max索引为止,但不包括max索引处的元素
3、结构体

声明方式

type Member struct {
    id     int
    name   string
    email  string
    gender int
    age    int
}

//使用方式如下
var m2 = Member{1,"小明","xiaoming@163.com",1,18} // 简短变量声明方式:m2 := Member{1,"小明","xiaoming@163.com",1,18}
var m3 = Member{id:2,"name":"小红"}// 简短变量声明方式:m3 := Member{id:2,"name":"小红"}
//如果只是想要为其中的两个字段赋值的话可以采用像 m3 这种形式

注意事项

结构体与数组一样,都是值传递,比如当把数组或结构体作为实参传给函数的形参时,会复制一个副本,所以为了提高性能,一般不会把数组直接传递给函数,而是使用切片(引用类型)代替,而把结构体传给函数时,可以使用指针结构体

指针结构体,即一个指向结构体的指针,声明结构体变量时,在结构体类型前加*号,便声明一个指向结构体的指针,如:

var m1 *Member
m1.name = "小明"//错误用法,未初始化,m1为nil

m1 = &Member{}
m1.name = "小明"//初始化后,结构体指针指向某个结构体地址,才能访问字段,为字段赋值。 

注意,指针类型为引用类型,声明结构体指针时,如果未初始化,则初始值为nil,只有初始化后,才能访问字段或为字段赋值。

另外,使用Go内置new()函数,可以分配内存来初始化结构休,并返回分配的内存指针,因为已经初始化了,所以可以直接访问字段。

var m2 = new(Member)
m2.name = "小红"

结构体与数组一样,是复合类型,无论是作为实参传递给函数时,还是赋值给其他变量,都是值传递,即复制一个副本。

在Go语言中,将函数绑定到具体的类型中,则称该函数是该类型的方法,其定义的方式是在func与函数名称之间加上具体类型变量,这个类型变量称为方法接收器

注意,并不是只有结构体才能绑定方法,任何类型都可以绑定方法,只是我们这里介绍将方法绑定到结构体中

func (m *Member)setName(name string){//将Member改为*Member
    m.Name = name
}

m := Member{}
m.setName("小明")
fmt.Println(m.Name)//小明

推荐阅读:Go Struct

*操作符作为右值时,意义是取指针的值,作为左值时,也就是放在赋值操作符的左边时,表示 a 指针指向的变量。其实归纳起来,*操作符的根本意义就是操作指针指向的变量。当操作在右值时,就是取指向变量的值,当操作在左值时,就是将值设置给指向的变量。

结构体“内部函数”的定义

以上面Member结构体为例,为其设置一个print函数

type Member struct {
	id     int
	name   string
	email  string
	gender int
	age    int
}

func (m Member) print()  {
	fmt.Println(m.name)
}

func main(){
	var member = &Member{}
	member.name = "admin"
	member.print()
}

类似接口如何设置以及“内部函数”定义可以查看文章:Go结构体和接口

4、new与make

Go语言中new与make都是内存分配的原语,简而言之,new用于分配内存,而mak用于slice、map和channel的初始化。

new(T)函数是一个分配内存的内建函数,new会为类型为T的新项分配已置零的内存空间,返回的是一个类型为*T的值,是一个指针,此指针指向的内容为类型对应的零值。由于指针变量初始化的时候其值为nil,所以不能直接初始化,看下面的例子:

var v *int
*v = 8
fmt.Println(*v)
//上面的代码会报错,因为v初始值为nil,不能为其直接进行赋值操作,可以修改为下面的操作
var v *int
v = new(int)
*v = 8
fmt.Println(*v)

make只用于slice、map和channel的创建,并返回类型为T的已初始化的非零值的值,出现这种差异的主要原因是这三种类型本质上为引用类型,这三种类型通过函数传参之后在函数内部修改将影响函数外部的值。

5、defer、panic与recover

defer 可能会影响函数的最终返回值,如下

func f() (result int) {
    defer func() {
        result++
    }()
    return 0
}

return xxx这一条语句并不是一条原子指令,含有defer函数的外层函数,返回的过程是这样的:先给返回值赋值,然后调用defer函数,最后才是返回到更上一级调用函数中。

存在多个defer修饰的函数时,最后面的函数最先执行,defer修饰的函数类似进栈操作,先进后出。

panic 内置函数停止当前goroutine的正常执行,当函数F调用panic时,函数F的正常执行被立即停止,然后运行所有在F函数中的defer函数,然后F返回到调用他的函数对于调用者G,F函数的行为就像panic一样,终止G的执行并运行G中所defer函数,此过程会一直继续执行到goroutine所有的函数。panic可以通过内置的recover来捕获。

recover 内置函数用来管理含有panic行为的goroutine,recover运行在defer函数中,获取panic抛出的错误值,并将程序恢复成正常执行的状态。如果在defer函数之外调用recover,那么recover不会停止并且捕获panic错误如果goroutine中没有panic或者捕获的panic的值为nil,recover的返回值也是nil。由此可见,recover的返回值表示当前goroutine是否有panic行为。

关于defer、panic与recover的详细示例阅读:[go defer,panic,recover详解 go 的异常处理](

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值