go语言基础(下) | 青训营笔记

43 阅读9分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

note9 函数

下面我们来看一下里面的函数,先看第五行到第七行代码,这是golang里面一个最简单的实现两个变量相加的函数,golang里面和进了很多语言不一样的是变量类型是后置的,golang里面的函数是原生支持返回多个值,但实际的业务逻辑代码里面几乎所有的函数都返回多个值,第一个值是真正的返回结果,第二个值是错误信息,参考第13到第16行代码这里的话,这个函数会返回两个值,一个值是真正的value,第二个是返回ok,就是是否存在。

note10 指针

golang也出过指针,当然相比c或者c++里面的指针,这里支持的操作非常有限,指针的一个主要用途就是对传入的参数进行修改,我们先看第五行到第七行这一个函数,这个函数它试图把一个变量加二,但是实际上上面这种写法是无效的,因为传入的参数实际上是个拷贝,这个+2是对一个拷贝进行的+2,并不起作用,如果我们需要起作用的话,我们需要把这个n写成一个指针类型,然后为了类型匹配调用的时候,会需要加一个&符号才能编译通过,同样这边运算的时候会加需要加一个*号。这样子我们就成功实现了对一个变量自增2的一个函数。

note11 结构体

结构体是带类型的字段的集合。

这边定义了一个user结构体,他包含两个字段name和password,我们可以用结构体的名称去初始化一个结构体变量。在初始化的时候我们需要传入每个字段的初始值,如果我们初始化的时候写出了那个字段的名字的话,我们也可以只指定一部分的值。

假如是没有初始化的字段的话,就会初始化成空值。对数字就0,对字符串就是空字符串,对于结构体我们来用点字段名字去读取或者写入结构体里面的内容,然后结构体也能作为函数的参数。作为参数的话,同样会有非指针和指针两种用法,如果你用指针的话,你就能实现对结构体的修改,然后也能在某些情况下避免一些大结构体拷贝的开销。

note12 结构体方法

在golang里面可以为结构体定义一些方法,这会非常类似于其他语言里面的类成员函数,比如在这个例子里面,我把上一个例子里面的checkPassword 的实现从一个普通函数改成了一个结构体方法,这样用户就可以用a点xxx,就是a点这个password 然后a点resetPassword这样去调用。

具体的代码修改,就是之前这个user,把它搬到在func后面函数名前面,然后左右加上括号即可,这样子的话,他就从一个普通函数变成了一个类成员函数,实现结构体方法的时候也会有两种写法,一种就是不带指针,第十行这里。另一种是带指针第14行这里。带指针的话,你就能对结构的进行修改。

note 13 错误处理

在golang里面,符合语言错误处理的习惯是使用一个单独的返回值来传递错误信息,不同于JAVA里面使用的异常,go语言的处理方式能够很清晰的知道哪个函数返回了错误,并且能够用简单的if else去处理错误。

在函数里面,我们可以在函数的返回值类型里面加一个error,这就代表这个函数可能会返回错误,在函数实现的时候,如果你要return,那你就需要同时return两个值,如果出现错误的话,你就return nil + error,这个error可以用errors.New()去创建,如果没有错误的话,那我就返回原本的结果和一个nil值。

在调用这些返回错误的函数的时候,接收需要写两个变量,比如这里写nil和error,然后调用完之后,你先要去判断一下error是否存在。如果error存在的话,你需要去做一些处理,比如打印error值、退出或者return。只有没有error的时候,你才能够去取真正的返回值,否则的话可能会出现空指针错误。

注意这里的“ ;”。

作用是:判断前面的err,一种固定的格式 前面声明变量 后面判断。两种方式等效!

note14 字符串操作

看一下golang里面的字符串操作,在标准库strings包里面有非常多的字符串工具函数,比如比如contains判断一个字符串里面是否包含另一个字符串。count字符串计数。index查找某个字符串的位置,join连接多个字符串,repeat重复多个字符串,我们还可以用len()这个内置函数,去获取字符上的长度,注意这里如果对于中文的话,可能一个中文会对应多个字符。

note15 字符串格式化

在标准库的fmt包里面有非常多的字符串格式化相关的方法,最常用的就是我们之前用的那个fmt.Println()这个就是打印多个变量,并且换行,然后就是fmt.Printf(),这个函数非常类似于c语言里面的printf()函数,不同的是在golang里面你可以很轻松的用%v来打印任意类型的变量,而不需要区分数字用%d,字符串用%s。

你可以用%+v来得到更加详细的结构,用%#v得到进一步详细的结构,右边可以看到这一个结构的打印,如果用%v的话会打印出值,然后它加v的话会打印出字段的名字和值,然后%v,他尽力的话会打印出结果体的整个构造的类型名称,还有他的字段名字和值,你可以用%.2f这种方式来打印出一个保留两位小数的浮点数.

note16 JSON处理

来看一下json操作,golang里面的操作非常简单,就是一个已有的结构题,我们什么都不需要做,只要保证每个字段的第一个字母是大写,也就是golang里面的公开字段,那么这个结构体就能用json.Marshal()序列化。序列化之后会变成一个byte数组,你可以简单理解为字符串,但是它打印的时候,你需要加一个string()类型转换才能打印出字符串,否则的话会打印出一些16进制的编码。

序列化之后的字符串,我们也可以简单的用json.Unmarshal()去反序列化到一个空的变量里面,空的变量在29行定义了。

一般情况下我们序列化出来的字符串,它的风格是大写字母开头,比如这里这个Name是大写,如果我们需要输出那种小写吓下划线风格的话,我们可以在结构体后面加一个tag,这里的话把这个大写的Age的字段名字改成小写,那么输出的这个age就变成小写了。

note17 时间处理

在golang里面最常用的时间处理就是time.Now()可以快速获取当前时间,我们也可以用time.Date()去构造一个带时区的时间,对于构造完的时间,有一系列方式,比如t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(),t.Second(),用这些方式来获取这个时间点的一些信息,你可以用t.Sub()对两个时间做一个减法,得到一个时间段,这个时间段可以得到有多少分钟,多少秒。

我们可以用time.format()去格式化一个时间到一个时间字符串,然后格式化的时候,这里不像很多编程语言里面又能是那种Yy yy mm dd,这里用的是一个特定的时间,"2006-01-02 15:04:05",然后这个时间是写在time包的官方文档上的,你也可以用他们time.Parse(),同样的用这个时间字符串的实例加一个字符串去解析成时间,在和某些系统交互的时候,我们经常会用到时间戳,你可以用time.unix()来获取一个时间。

注意:转换的时间格式必须是 "2006-01-02 15:04:05"

note18 数字解析

我们再来看一下字符串和数字之间的转换。

在golang里面关于字符串和数字之间的转换都在strconv这个包下,这个就是string、converse这两个单词的缩写,我们可以用ParseInt和或ParseFloat来解析一个字符串,在ParseInt这边有三个参数,一个参数就是字符串,第二个参数是代表进制,可以是十进制或者八进制或者十六进制,如果填零的话,就那个自动去推测,后面64就代表我返回的是一个64位精度的整数

我们也可以用来Atoi把一个时间制字符串转成数字,同样的,我们可以用itoa把数字转为字符串,如果输入不合法的话,这些函数都是返回一个错误,就告诉你数字不合法。

note19 进程信息

再来看一下golang里面来获取一些进程相关的信息,我们可以用os.Args来获取进程在执行的时候的一些命令行参数,比如上面的话,我们go run xxxx.go,然后后面加abcd来接执行一个go的原文件,那么输出的os.Args长度是5,第一个成员代表二进制自身的路径加名字,这里是一个临时目录,后面才是abcd,然后你可以用os.Getenv() 或者os.Setenv分别来获取或者写入环境变量,你可以用exec.Command()来快速启动子进程并且获取其输入输出。