Go 语言趣学指南 | 青训营

208 阅读6分钟

1.基本的编程知识

高级编程语言大多数都有变量、三大结构(循环、循序、选择)以及函数概念。这些是编程的基本概念。是我们入门任何一中编程语言的第一部分。下面我将从这三种概念来学习golang。

1.1 变量

在golang 中数据类型有以下这些。

1布尔型 布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
2数字类型 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
3字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
4派生类型: 包括: (a) 指针类型(Pointer)(b) 数组类型 (c) 结构化类型(struct) (d) Channel 类型 (e) 函数类型 (f) 切片类型 (g) 接口类型(interface) (h) Map 类型

指导数据类型我们就可以声明变量了。

// 1
var count int = 10
// 等价于下面这种方式 声明和赋值 两个过程
var cnt int //声明
cnt = 10  //赋值
// 2
a := 10

第一种方法是一种比较常见的声明方式,常常用于我们只知道数据类型,但是不知道,数据类型中的数值是多少。当我们声明一个变量时,系统会给赋值为给定类型的0值,例如数值类型为0,指针类型为1。第二种常常用于我们接受函数的返回值。

1.2三大结构

顺序结构: 我们编程的最基本的结构,程序会阿按照我们的代码顺序执行,当然如果代码不影响我们的程序的正确的输出,编译器会进行指令重排。这个不是我们入门时要关注的。

循环结构: 在c中最为出名的结构就是for和while以及do while。在go中,循环结构,常常表现这种形式。

//死循环
for {
    ...
}
//遍历可迭代对象的循环
var array = []int{1,2,3,4,5,6};
for idx,val := range array {
    ...
}
//以及最经典的for 循环
for i:= 0;i<10;i++ {
    ...
}

在循环中我们依然可以用break和continue来推出当前循环和本轮循环。

以及选择结构:

//switch
switch var {
    case 100:
        ...
    case 90,80,70,60:
        ...
    default:
        ...
}
//if else
if var == 100 {
    
} else if var >=60 {
    
} else {
    
}

需要注意的是,golang中的 { 不能作为一行的开始,这就需要我们要求我们必须注意我们的代码格式。

1.3函数

在golang中,函数的定义如下:

func div(var1 int,var2 int)(int,error){//没有返回值,就不写返回类型
    if var2 == 0{
        return 0,errors.New("can`t div with 0")
    }else{
        return var1/var2 nil
    }
}
//其中nil表示空,如果一个函数没有错误,并要求返回值时,我们就常常返回一个空。另外nil也表示空pointer。

上述函数声明我们可以知道了如何声明一个函数。同时知道了func可以返回多个变量。

我们都知道不要返回局部变量的指针和引用,因为他们被返回后,被指向的变量就已经失效了。但是golang可以,因为编译器会帮我们将变量转移到heap区中。还有gc会帮我们完成内存的清理工作。

2.数组、切片、指针以及结构体

2.1 从数组到指针

我们声明数组时,它在计算机会这样表示。

var arr = [4]int {1,2,3,4}

程序会在stack中分配连续的4x4Byte的内存地址,并将变量赋值。但是我们要注意,如果要以数组作为参数为函数赋值,我们无法在函数中,修改对应的数组,因为golang 传递函数是传递整个数据结构。也就是新开辟一个stack保存函数的调用stack。那么这样不仅耗费巨大,而且还不能修改对应的数组。

那么我们有一种新的数据结构----切片。

切片是指向原数组的(收集器),本质是指针。

常用的声明有这样

arrSlice1 = arr[:] {1,2,3,4}
arrSlice2 = arr[1:4] {2,3,4}

既然切片本质上是指针那么就可以解决上面的问题。

//go也是通过 &*来从普通变量得到指针和解引用的。
例如
age := 10
pAge = &age
*age = 11

我们通过new函数可以将对应的变量开辟到heap区中。返回对应函数的指针。

make函数可以帮助我们在heap中开辟一个切片。

例如:

type struct People {
    Age int
    Name string
}
abc = new(People)
arr = make([]string,10)

上述过程中,我们定一了一个结构体People,通过new开辟的一个People类型的空间,以及使用make函数开辟了长度为10的string数组的切片。

如果你熟悉面向对象编程,你会发现在golang中并没有类。但是golang中也提供结构体方法。

例如

func (p People) sayHello(){
    fmt.Println("hello ",p.Name)
}

除此之外,你会发现,如果在结构体中将对应字段的首字母改成小写。那么编译器会报错。这是因为在golang中编译器会根据首字母大小写来判断是否对外界暴露变量。

tag是go中的一个特性,这个特性可以帮助我们完成许多事情。例如自动帮我们解析json格式数据。

type Student struct{
    ID int64 `json:"id"`
    Name string `json:"name"`
}
//那么我们就可以使用json.Marshal(xxx)直接将结构体解析成对应json的数据结构。
p := Student{
    ID:10,
    Name:"lisan",
}
data,err := json.Marshal(p)
{"id":10,"name":"lisan"}

2.2继承去那了?

在go中没有继承,取而代之的是组合。

例如:

type People struct {
    Name string
    Age 12
}
func (p *People)XXX(){
    ...
}
type Student struct {
    People
    ID int64
}
stu := Student{
    People {
      xxx  
    },
    xxx
}
stu.XXX()

上述过程中就是组成,通过组成我们可以使用对应组成对象的方法。

2.3鸭子类型和接口

什么是鸭子类型,如果一个变量有鸭子这种类型的所有方法,那么他就是鸭子。

在go中,interface就是来描述鸭子类型。如果一个变量实现了某个接口的所有方法,那么我们就可以使用这个接口类型来替代原有的类型。通过这种方式表现出多态。

type Speaker interface {
    speak()
}
type People struct {
}
func (p *People)speak(){
    ...
    fmt.Println("i am here")
}
var s Speaker = People{}
s.speaker()
// stdout: i am here

其中我们最常用的是空接口,在go的1.18 这个空接口有个别名为Any

他的定义如下:

type any inteface{}

既然空接口没有方法,那么我们可以使用any来接受任意类型的数据,也就是说我们可以使用空接口当作范型来用。

今天的介绍到此为之,下次我将讲解go的网络库和sync库,来完成go的并法控制和网络编程。