一、前言
接着上一个博客(Go 语言入门--Go语言基础语法 Part 1)写,我们继续来学习Go语言的基础语法
二、基础语法
11.结构体
结构体是带类型的字段的集合,简单来说,就是一些类型加起来的集合。
在go语言中,结构体的定义和使用和C语言类似,但是也有形式上的不同,但是使用方式还是一样的
示例:
//定义一个名为user的结构体
type user srtuct {
name string
password string
}
func main(){
//在主函数中定义结构体变量
//第一种方式,用字段名进行匹配
a := user(name :"xioaming" , password:"1024")
//第二种方式,自动匹配字段
b := user("xiaoming","1024")
//第三种方式,先定义一种字段,只对一部分字段进行初始化
c := user(name:"xiaoming")
c.password = "1024"
//第四种方式,先定义,后初始化
var d user
d.name = "xiaoming"
d.password = "1024"
}
在go语言中,结构体经常会作为参数传入自定义函数中,而且经常作为指针传入,这样能够实现对结构体的修改,也可以在避免一些大结构体的拷贝开销。
注:拷贝开销:指的是一般情况下,传入函数的参数只是对于参数值的拷贝,而不是原值。 示例(续上):
//二者的效果是一样的
func checkPassword(u user , password string) bool{
return u.password == password
}
func checkPassword(u *user , password string) bool{
return u.password == password
}
12.结构体方法
在go语言中,我们可以为结构体定义方法,就像java中给类写方法一样,这样我们就可以在实例中调用这个方法,简单说,就是我们可以在定义结构体变量之后,通过调用其中的方法完成一些操作
type user struct{
name string
password string
}
//接下来给这个结构体定义方法
func (u user) checkUser(name string , password string) bool{
return name == u.name && password == u.password
}
func (u *user) setPassword(password string){
u.password = password
}
其定义方法很简单,就是把结构体变量放在函数名前面,并且需要加上括号,这样的话,我们就可通过 a.checkPassword("xxxx") 对方法进行调用。
并且从我上面的代码可以看出,结构体方法可以有两种写法,一种是带指针的写法,一种是不带指针的写法,区别在于带指针的写法可以修改结构体中的字段。
a := user(name:"xiaoming", password:"123456")
a.setPassword("1234567");
fmt.println(a.password) //1234567
13.错误处理
和Java中需要使用异常来处理错误信息不同,在go语言中,我们通常会用一个单独的返回值来传递错误信息 注意:在使用这个时,需要提前引入errors 处理过程如下:
type user struct{
name string
password string
}
func findUser(users []user, name string ) (v *user, err error){
for _,u := range users{
if u.name == name{
return &u,nil
}
}
return nil,errors.New("not Find")
}
我们可以通过在参数列表中加上一个error,就代表这个函数可能会出错
然后我们可以通过简单的if-else语句来处理错误,并且可以很清晰的看出是哪个函数出了错。
如果出了错,那么就返回 nil 和 error
如果没有出错,那么就返回 原本的结果 和 nil
注:在 Golang 中,nil 是一个预定义的标识符,在不同的上下文环境中有不同的含义,但通常表示“无”、“空”或“零值”。nil 可以赋值给指针、切片、map、通道、函数以及接口类型的变量。
下面出如何通过返回值来判断和处理错误,判断错误的写法还是比较固定的
//续上
func main(){
u,err := findUser([]users {{"wang" , "123456" },{"guan","1234567"}} ,"wang")
if err != nil {
fmt.println(err)
return
}
fmt.println(u.name) //wang
}
14.字符串操作
前提:引入 strings
在go语言中,我们可以通过string工具库来使用一些工具函数,比如:Contains用于判断一个字符串中是否包含另一个字符串,Count用于字符串计数,Index用于字符串的查找位置,Join用于连接多个字符串,Repeat用于重复多个字符串,Replace用于替换字符串
下面是使用示例:
package main
import{
"fmt"
"strings"
}
func main(){
a := "hello"
fmt.println(strings.Contains(a,"ll")) //true
fmt.println(strings.Count(a,"l")) //2
fmt.println(strings.HasPrefix(a,"he")) //true
fmt.println(strings.HasSuffix(a,"llo")) //true
fmt.println(strings.Index(a,"ll")) //2
fmt.println(strings.Join([]string{"he","llo"},"-")) //he-llo
fmt.println(strings.Repeat(a,2)) //hellohello
//func Replace(s, old, new string, n int) string
//用法:返回将s中前n个不重叠old子串都替换为new的新字符串,如果n<0会替换所有old子串。
fmt.println(strings.Replace(a,"e","E",-1));
fmt.println(strings.Split("a-b-c","-")) //[a b c]
fmt.println(strings.ToLower(a)) //A
fmt.println(len(a)) //5
//中文的对应字节不同
fmt.println(len("你好")) //6
}
15.字符串格式化
在fmt标准库中有很多和字符串格式相关的方法,printf和c中的printf就很像,但是有一点不同,在go语言中,我们可以用%v来打印任何类型的参数,也可以用%+v来打印更详细的参数,还有%#v则更加详细
type point struct{
x,y int
}
func main(){
p := point(1,2)
fmt.printf("%v",p) //{1 2}
fmt.printf("%+v",p) //{x:1 y:2}
fmt.printf("%#v",p) //main.point{x:1 y:2}
}
16.JSON处理
前提:需要引入 encoding/json
这里只涉及到标准库中的JSON处理
其实go语言中的JSON处理是非常简单的,我们只需要把结构体中的字段名的第一个字母大写即可,这样这个字段就成了公开字段 ,那么这个结构体就可以用 json.Marshal 序列化,变成一个JSON格式的字符串
序列化之后字符串也可以通过 json.Unmarshal 反序列化 到一个空变量中,这样默认序列化出来的字符串,输出会是以大写字母,也就是定义的公开字段的方式输出,我们可以用tag的写法,修改JSON结果里面的字段名
type userInfo struct{
Name string
Age int 'json:"age"'
Hobby []string
}
func main(){
a:= userInfo{"wang",18,{"basketball","football"}}
buf,err := json.Marshal(a) //buf ---- [123 34 78 ……]
if err != nil{
panic(err)
}
fmt.println(string(buf)) //{"Name":"wang","age":18,"Hobby":["basketball","football"] }
var user
err = json.Unmarshal(buf,&user) //把buf中的json反序列化到b中,返回一个可能的错误
if err != nil{
panic(err)
}
fmt.println(user) //{"Name":"wang","age":18,"Hobby":["basketball","football"] }
}
注:在Go语言中,panic是一个内置的函数,用于在程序遇到严重的错误时触发一个不可恢复的异常。当panic被调用时,它会暂停正常的程序执行流程,打印出错误信息,并可能调用所有的 goroutine 中的 defer 函数,然后结束程序。这是处理错误的一种非常强烈和直接的方式。
defer语句是Go语言中的一个精华特性,用于在函数结束前自动执行代码。当函数结束时,defer语句中的代码会以逆序执行,即使函数是通过返回语句或恐慌结束的也会如此。这通常用于执行清理工作,比如关闭文件或网络连接。
具体的相关和用法会在后面再进行普及
17.时间处理
前提:需要引入time
在go语言中时间操作是很简单的,我们最常用的就是利用time.Now()获取现在的时间,也可以用time.Date()去构造一个带时区的时间。
func main(){
now := time.Now()
fmt.println(now) //2024-11-22 09:59:14.2642387 +0800 CST m=+0.010202701
t := time.Date(2024,2,12,1,25,36,0,time.UTC)
fmt.println(t) //2024-2-12 01:25:36 +0000 UTC
}
注:可能有很多会有这样的疑问,为什么使用Now的时候,秒数后有七位,m又是什么
前提知识:时间戳:时间戳是一种用于唯一标识时间的方法,通常表示为自某一特定时刻或者起点(如Unix纪元1970年1月1日午夜)以来的秒数或者毫秒数。在计算机科学中,时间戳常用于跟踪日志、同步处理和存储事件数据。
1.秒数有七位:对于时间戳来说,一般使用秒级或者毫秒级,采用浮点数或定点数来表示小数部分,为了在大部分时候满足精度,我们会用七位小数来表示毫秒级的小数部分。
2.m:m 就是 Monotonic Clocks,意思是单调时间的,所谓单调,就是只会不停的往前增长,不受校时操作的影响,这个时间是自进程启动以来的秒数。
我们也可以对时间进行格式化,可以用YYYY-MM-dd的形式,因为time库中定义了年、月、日、时、分、秒、周、时区的多种表现形式,如下:
- 年: 06/2006
- 月: 1/01/Jan/January
- 日: 2/02/_2
- 时: 3/03/15/PM/pm/AM/am
- 分: 4/04
- 秒: 5/05
- 周: Mon/Monday
- 时区:-07/-0700/Z0700/Z07:00/-07:00/MST
所以我们可以自由通过这些进行组合,达到自己想要的输出形式
func main(){ //续上
fmt.println(t.Format("2006-01-02 15:04:05")) //2024-02-12 01:25:36
}
上面有很多方法来获取这个时间点的年月日小时分钟秒,然后也能用点 sub 去对两个时间进行减法,得到一个时间段。时间段又可以去得到它有多少小时,多少分钟、多少秒。 上面有很多方法来获取这个时间点的年月日小时分钟秒,然后也能用点 sub 去对两个时间进行减法,得到一个时间段。时间段又可以去得到它有多少小时,多少分钟、多少秒
func main(){ //续上
fmt.println(t.Format("2006-01-02 15:04:05")) //2024-02-12 01:25:36
fmt.println(t.Year(),t.Month(),t.Day(),t.Hour(),t.Minute()) //2024 2 12 1 25
diff := now.Sub(t)
}
我们还可以通过一些方法来转换时间的格式 比如time.Parse();
func main(){ //续上
t2 := time.Parse("2006-01-02 15:04:05","2024-2-12 01:25:36")
fmt.println(t2 == t) //true
}
在一些系统交互或者方法中需要用到时间戳,我们也可以通过方法来拿到时间戳
func main{
now := time.Now()
// 取时间戳
fmt.Println(now.Unix()) // 当前时间戳
fmt.Println(now.UnixMilli()) // 毫秒级时间戳
fmt.Println(now.UnixMicro()) // 微秒级时间戳
fmt.Println(now.UnixNano()) // 纳秒级时间戳
fmt.Println(now.Nanosecond()) // 时间戳小数部分 单位:纳秒
}
18.数字解析
前提:引入 strconv
在go中,我们是说的数字解析,就是把字符串形式的数字转换为数字形式,而数字形式就是说可以把这些数字转换为整数或浮点数
最基本的方法是当我们有一个以字符串形式存在的10进制数字时,我们想把它转换成一个整数。为了做到这一点,我们可以利用最广泛使用的 Atoi() 函数。
func main(){
i:="111"
res,err = strconv.Atoi(i)
if err != nil{
fmt.println("error")
return
}
fmt.Println("The number now is:", res) //111
fmt.Printf("The type of the number is: %T", res) //int
}
还有两种可以把字符串转化为数字形式的函数
ParseInt()的语法
number, error := strconv.ParseInt(string, base, bitSize)
ParseFloat()的语法
number, error := strconv.ParseFloat(string, bitSize)
注意:我们可能遇到"0X1234"这种十六进制的字符串,这时我们只能有ParseInt()来转化他
三、结语:
今天的学习到此为止,现在我们基本学习了go语言基础语法,之后的就是尝试着敲出自己的代码了