这是我参与「第三届青训营 -后端场」笔记创作活动的的第三篇笔记
看到这的朋友们,如果没有看过我写的Go语言基础(一)的话会很懵,建议看一下 Go语言基础(一)
Go语言基础(二)
复杂数据类型
上次学到了数组,这里我开始学习切片,切片作为Go最特殊的一种数据类型,是我们必须需要掌握的。
切片室对底层数组一个连续片段的引用(该数组称为相关数组,通常是匿名的),所以,切片是一个引用数据类型。
切片类型表示其元素类型的所有数组切片的集合。
未初始化切片的值为nil。
对于nil值的理解
其实刚开始看到这个值的时候,我首先想到的是Java中的null值,但是其实是不相同的。
在go中,非指针类型的对象是不能赋值为nil的
var b []int
if b == nil{
fmt.Println("b的值为nil")
}//b的值为nil
并且非指针类型的对象也不能和nil判断,会报编译错误
b := 123
if b == nil{
fmt.Print("b的值为nil")
}//cannot convert nil to type int
切片(slice)
我们先来说说切片,切片有长度,有容量且容量>=长度
在Go中有三种定义切片的方法:
- 其实数组就是一种特殊的切片,只不过这时候容量是等于长度的
a := []int{1,2,3,5,4}//看起来我们定义了一个数组a,其实他也是一个切片
- 使用make()函数来创建一个切片
b := make([]int,3,10)//切片c的长度为3,容量为10
//var slice = make([]type,length,capacity)
- 从数组或者切片中生成一个新的切片
var c = a[1:3:5]
//这个切片c就是切片a的一部分,只不过,容量为5,从a[1]开始到a[3]结束
//var new = old[low:high:max],这里的长度为high-low,容量为max-low
//这里的low-high 注意,是左闭右开的
//注意切片取值时,索引值大于长度会导致异常发生
//假如这里我写了一段代码:d := c[2] 这样就会导致越界
也可以利用append()或copy()来创建切片,不过这种方式是在原切片的基础上实现的!
字典(map)
在Java中我们知道,Map是一个k-v键值对,同样的,Go中也是一样的,map也是k-v键值对,都是无序的(无论是k还是v,如果想给他们排序,可以将k或者v放入切片中,然后通过排序方法给切片排序)
关于map的初始化:
- 使用make()函数
maps := make(map[string]int,100)
//这里定义了一个map,k的类型为string,v的类型为int,容量为100
//make(map[keyType]valueType)
- 直接定义
var a = map[string]int{}
//定义了一个map a 里面没有内容
var b = map[string]int{"1":1,"2",2}
//定义了一个map b 里面有内容
var c map[string]int
//c是一个nil,注意往c中放值的时候会报错,因为这里仅仅是一个声明并没有初始化
//这里我理解成Java中仅仅声明了一个对象而没有去实例化
删除操作
在map中删除,直接使用delete(map,key),删除即可
函数
我们先来看函数的语法
func 函数名(参数列表)(返回值列表) {
函数逻辑
return
}
我们可以看到Go中返回值与Java不一样,在Java中只能有一种返回值,而在Go中却是多个返回值,这里我的意思并不是可以返回不同的值,而是可以同时返回不同的值。
func jiajian(a int, b int) (int, int) {
return (a + b), (a - b)
}//定义了一个两个返回值的函数
add, reduce := jiajian(1, 2)//定义两个变量接收这两个返回值
说到函数,在Java中我们可以使用函数重载,在Go中这样操作是不被允许的
函数重载:指的是方法名相同,但是返回值或参数类型不同的两个或多个函数
在Go中,也是有指针的,和C/C++类似,但是Go中的指针用处非常有限,一般都使用在函数参数上,用于传给函数一个引用。
内置函数
在Go中,有很多内置函数,例如我们在学习切片的时候使用的make()函数,还有new()函数
len()、cap()、append()、copy()、delete()、close()
complex()、real()、imag()、panic()、recover()。。。。
这里就不再一一赘述具体的请看Go开发手册
匿名函数
在go中支持匿名函数,但是这种函数不能单独存在,必须依托于一个变量
a := func(x, y int) int {
return x + y
}
b := a(1, 2)
fmt.Print(b)//3
//也可以使用下面这种写法,直接在函数结尾加上括号表示赋值,需要注意的是
//这个()无论如何也不能移除即使没有参数
c := func(x, y int) int {
return x + y
}(1, 2)
fmt.Print(c)
结构体和接口
在这里我将结构体简单理解为Java中的类,我们先看一看结构体的语法结构
type 结构体名 struct{
filed1 type
filed2 type
......
}
这里我定义了一个结构体 需要注意的是,go中的结构体十分简单,它不能在结构体中写方法,只能写在结构体外,使用接收器来接收,这里我就先不赘述,后面我在详细的说。
匿名字段
因为Go语言是一种面向对象的编程语言,但是他没有封装,继承等这类思想,我们可以通过添加匿名字段来实现继承的思想
type yl struct {
name string
age int
student
}
type student struct{
class string
grade string
}
//这样就可以使用继承的思想了,
//我在结构体yl中定义了一个student匿名字段,这个时候,yl结构体中继承了student的成员变量
我们称上面这种思想叫嵌入或内嵌。
结构体中的字段,也可以使用结构体类型的,我们称这为聚合。
接口
接口类型是Go语言的一种数据类型。和Java类似接口都是定义一组方法,而不能自我实现, 只能由其他非interface类型实现。
我们在开发Java程序的时候,在SpringBoot中我们都知道约定大于配置的法则
在Go中,我们也有一个类似的法则,就是当一个接口是一个单方法接口的时候,我们应在方法名称后加er,,当er不合适的时候,我们在前面加I或者在后面加able
我们在Go中可以实现一个接口类型的一些方法,只有我们实现了该类型的所有方法的时候,我们才称之为实现了该接口!
在接口中,可以内嵌其他接口,可以类比成Java中接口的继承,但是下面这种是不行的
type Suc interface {
Suc1
hello()
}
type Suc1 interface {
Suc
hello1()
}
也不能自己内嵌自己
type Suc interface {
Suc
hello1()
}
上面这两种内嵌都是错误的
下面这种才是正确的接口的内嵌
type Suc interface {
hello()
}
type Suc1 interface {
Suc
hello1()
}
接口可以内嵌多个其他接口,通过这样的方式来实现多重继承。
方法
提到方法,很多朋友可能很诧异,因为我在前面已经说过了函数,为什么又要说方法,难道它们不是一个东西吗?
这点我在前面已经说过了,在我的理解中,方法和函数它们不是一个东西
函数是独立与类的一种方法,它不属于任何类,而方法则是在类中才存在的
方法可以理解成存在于类中的函数!
在Go的方法中,存在一种与Java不同的东西,那就是接收器,我理解的接收器,作用是匹配的作用 ,多的不说,咱们代码见真章!
type yl struct {
name string
age int
}
func (a yl) PrintName() {
fmt.Print(a.name)
}
我们乍一看和之前没有任何区别,但是还是很不一样的,我们看一下之前函数的语法
func 函数名(参数列表)(返回值列表) {
函数逻辑
return
}
这样看来就有很大不一样了吧,在这里(a yl)这就是一个接收器,这个接收器就相当于与yl这个结构体绑定,然后我们可以通过yl类的对象.方法名来调用这个方法,这样我们就可以写出方法的语法结构了。
func (参数名字 type) 方法名(参数列表)(返回值列表) {
语法逻辑
}
注意接收器中的参数类型是在其他的或非本地的包里定义的,则会报错!!
方法也非为指针方法和值方法,这样说很笼统,简单来说,就是,在接收器这里,使用指针的就是指针方法!!!这里就不再赘述,指针方法和值方法的区别,这个和Java中,引用传递和值传递类似。
基础部分就先写到这里吧,很感谢小伙伴看到这里,不过这仅仅是Go语言基础的基础,还有很多要学习哦,加油!!!