首页
About Me
Search
1
linuxea:gitlab-ci之docker镜像质量品质报告
49,485 阅读
2
linuxea:如何复现查看docker run参数命令
23,755 阅读
3
Graylog收集文件日志实例
18,638 阅读
4
linuxea:jenkins+pipeline+gitlab+ansible快速安装配置(1)
18,438 阅读
5
git+jenkins发布和回滚示例
18,235 阅读
ops
Openppn
Sys Basics
rsync
Mail
NFS
Other
Network
HeartBeat
server 08
Code
Awk
Shell
Python
Golang
vue
virtualization
KVM
Docker
openstack
Xen
kubernetes
kubernetes-cni
Service Mesh
Data
Mariadb
PostgreSQL
MongoDB
Redis
MQ
Ceph
TimescaleDB
kafka
surveillance system
zabbix
ELK Stack/logs
Open-Falcon
Prometheus
victoriaMetrics
Web
apache
Tomcat
Nginx
自动化
Puppet
Ansible
saltstack
Proxy
HAproxy
Lvs
varnish
更多
互联咨询
最后的净土
软件交付
持续集成
gitops
devops
登录
Search
标签搜索
kubernetes
docker
zabbix
Golang
mariadb
持续集成工具
白话容器
elk
linux基础
nginx
dockerfile
Gitlab-ci/cd
最后的净土
基础命令
gitops
jenkins
docker-compose
Istio
haproxy
saltstack
marksugar
累计撰写
667
篇文章
累计收到
111
条评论
首页
栏目
ops
Openppn
Sys Basics
rsync
Mail
NFS
Other
Network
HeartBeat
server 08
Code
Awk
Shell
Python
Golang
vue
virtualization
KVM
Docker
openstack
Xen
kubernetes
kubernetes-cni
Service Mesh
Data
Mariadb
PostgreSQL
MongoDB
Redis
MQ
Ceph
TimescaleDB
kafka
surveillance system
zabbix
ELK Stack/logs
Open-Falcon
Prometheus
victoriaMetrics
Web
apache
Tomcat
Nginx
自动化
Puppet
Ansible
saltstack
Proxy
HAproxy
Lvs
varnish
更多
互联咨询
最后的净土
软件交付
持续集成
gitops
devops
页面
About Me
搜索到
54
篇与
的结果
2023-11-21
linuxea:表单中select处理后端数据
在已有的表单中添加一个select菜单。dtype作为新增的一列 const fromUserAdd = reactive({ id: "", // 添加用户的用户名 name: "", domain_status_check: "", domain_tls_check: "", prompt_time_day: "", update_time: "", dtype:"", })但是dtype的数据是从另外一个结构获取,已知的后端接口数据格式如下{ "code": 200, "msg": "success", "data": [ { "id": 0, "name": "test1" }, { "id": 0, "name": "test2" } ] }要从接口数据获取值,我们重新声明2个变量进行赋值 const selectvalue ="" const Options = ref([])而后在函数中赋值这里省略一些调用的判断和接口 const handleAddAlert = async () => { let res = await proxy.$api.dingtalkgetname() Options.value = res }而后需要return return { handleAddAlert, selectvalue, Options, ...回到form表单v-model="fromUserAdd.dtype"绑定新增的字段@focus="handleAddAlert"指定创建的函数el-option中v-for循环Options取值即可 <el-form> <el-row> <el-col> <el-form-item label="选择一个告警媒介"> <el-select placeholder="请选择" v-model="fromUserAdd.dtype" @focus="handleAddAlert"> <el-option v-for="item in Options" :value="item.name" > </el-option> </el-select> </el-form-item> </el-col> </el-row>如下
2023年11月21日
4 阅读
0 评论
0 点赞
2020-12-22
linuxea:go切片排序(41)
对所有切片排序9.1切片排序示例创建一个包含数组的切片list := [][2]int{{1,3},{5,9},{4,7},{6,2},{0,8}}排序的规则是使用每个元素的第二个元素(索引为1)比较大小使用sort.Slice进行排序Slice传入list,而后是一个匿名函数,索引为i和j,返回一个bool ,索引i和j是需要自己进行比较。如下list[i][1] > list[j][1]list中索引i第二个元素1进行比较,那分别就是{1,3},{5,9},{4,7},{6,2},{0,8}中的,3,9,7,2,8进行排序sort.Slice(list,func(i,j int)bool{ return list[i][1] > list[j][1] })代码块package main import ( "fmt" "sort" ) func main(){ list := [][2]int{{1,3},{5,9},{4,7},{6,2},{0,8}} sort.Slice(list,func(i,j int)bool{ return list[i][1] > list[j][1] }) fmt.Println(list) }运行[root@linuxea.com /opt/Golang/work5]# go run sort.go [[5 9] [0 8] [4 7] [1 3] [6 2]]对结构体排序9.2结构体排序我们定义一个结构体,如下type User struct { Id int Name string Score float64 }而后赋值给users,如下:users := []User{{3,"m",6},{2,"a",5},{1,"r",7},{4,"k",8}}使用sort.Slice进行排序,在返回值上,使用.score排序score,score的值现在是6,5,7,8,排序后的结果是5,6,7,8 sort.Slice(users,func(i,j int)bool{ return users[i].Score < users[j].Score })如下:package main import ( "fmt" "sort" ) type User struct { Id int Name string Score float64 } func main(){ users := []User{{3,"m",6},{2,"a",5},{1,"r",7},{4,"k",8}} sort.Slice(users,func(i,j int)bool{ return users[i].Score < users[j].Score }) fmt.Println(users) }运行[root@linuxea.com /opt/Golang/work5]# go run sort2.go [{2 a 5} {3 m 6} {1 r 7} {4 k 8}]我们还可以对id排序,修改成users[i].Id < users[j].Id即可package main import ( "fmt" "sort" ) type User struct { Id int Name string Score float64 } func main(){ users := []User{{3,"m",6},{2,"a",5},{1,"r",7},{4,"k",8}} sort.Slice(users,func(i,j int)bool{ return users[i].Id < users[j].Id }) fmt.Println(users) }运行[root@linuxea.com /opt/Golang/work5]# go run sort2.go [{1 r 7} {2 a 5} {3 m 6} {4 k 8}]
2020年12月22日
2,640 阅读
0 评论
0 点赞
2020-12-17
linuxea:go方法(40)
方法是为特定类型的定义的,方法和函数类似,只能由该类型调用的函数。定义:定义一个方法必须要添加一个接收者函数,接收者必须是自定义的类型-调用:调用方法通过自定义类型的对象.方法名进行调用,在调用过程中对象传递给方法的接收者(值类型,拷贝)指针接收者:当使用结构体指针调用接收者方法时,go编译器会自动将指针对象解引用。当使用结构体对象调用方法时,go编译器会自动将值对象取引用为指针调用方法。该使用值接收者还是指针接收者,取决于是否现需要修改原始结构体,若不需要修改则使用值,若需要修改则使用指针。若存在指针接收者,则所有方法是用指针接收者。对于接收者为指针类型的方法,需要注意在运行时若接收者为nil会发生错误。那么需要初始化。8.方法方法值/方法表达式: 方法也可以赋值给变量,存储在数组,切片,映射中,也可以作为参数传递给函数,也可以作为返回值进行返回。方法有两种,一种使用对象/对象指针调用的方法值。另外一种是有类型/类型调用的方法表达式。方法值在方法表达式赋值时若方法接收者为值类型,则在赋值时会将值类型拷贝(若调用为指针则自动解引用拷贝)8.1方法定义和获取示例定义一个类型type Dog struct{ Name string }定义一个方法来调用,在call函数名前加括号定义类型和变量值,如下func (dog Dog)Call(){ fmt.Printf("%s:call",dog.Name) }这样意思是只有dog类型的Dog才能调用而后在调用的时候,直接调用func main(){ dog := Dog{"大白"} dog.Call() }在Call方法func (dog Dog)Call(){fmt.Printf("%s:call",dog.Name)}中,在调用的时候,外面(dog Dog)中的dog会传递给Dog.调用call方法如下:package main import "fmt" type Dog struct{ Name string } func (dog Dog)Call(){ fmt.Printf("%s:call",dog.Name) } func main(){ dog := Dog{"大白"} dog.Call() }运行[root@linuxea.com /opt/Golang/work5]# go run ffa.go 大白:call8.2方法修改我们修改上面定义的方法 dog.Name = "雪子" dog.Call()如下package main import "fmt" type Dog struct{ Name string } func (dog Dog)Call(){ fmt.Printf("%s:call\n",dog.Name) } func main(){ dog := Dog{"大白"} dog.Call() dog.Name = "雪子" dog.Call() }运行[root@linuxea.com /opt/Golang/work5]# go run ffa.go 大白:call 雪子:call包外调用如果要在包外调用,就需要写一个函数能够在包外调用。我们先看普通的调用,如下:func (dog Dog) Setname(name string){ dog.Name = name }func main(){ dog.Name = "雪子" dog.Call() dog.Setname("ss") }运行[root@linuxea.com /opt/Golang/work5]# go run ffa.go 大白:call 雪子:call 雪子:call你会发现这样的修改是没有作用, 这是因为结构体是值类型,调用方法的时候,只是复制了一份,前面和后面的dog是没有关系的。如果要进行修改,就要修改成指针的接收方法。func (dog *Dog) PsetName(name string) { dog.Name = name }这样一来调用的时候就需要获取他的指针调用,取地址,如下 (&dog).PsetName("Psetname") dog.Call()这里也可以直接使用dog.PsetName("Psetname"),因为PsetName函数中的方法*Dog是指针,会自动取引用。这是语法糖会自动进行转换。自动取引用和解应用只会发生在接收者,接收者参数才会,而函数参数是不会的,函数需要手动解引用如下:package main import "fmt" type Dog struct{ Name string } func (dog Dog)Call(){ fmt.Printf("%s:call\n",dog.Name) } func (dog Dog) Setname(name string){ dog.Name = name } func (dog *Dog) PsetName(name string) { dog.Name = name } func main(){ dog := Dog{"大白"} dog.Call() dog.Name = "雪子" dog.Call() dog.Setname("ss") dog.Call() (*&dog).PsetName("Psetname") dog.Call() }运行[root@linuxea.com /opt/Golang/work5]# go run ffa.go 大白:call 雪子:call 雪子:call Psetname:call如果指针要调用值就可以使用*pog,如下 pdog := &Dog{"pdog"} (*pdog).Call()这里也可以直接使用pdog.Call(),调用者是一个指针类型,方法接收者是值类型,会进行自动解引用。 而(*pdog).Call()是解引用自动取引用和解应用只会发生在接收者,接收者参数才会,而函数参数是不会的,函数需要手动解引用运行[root@linuxea.com /opt/Golang/work5]# go run ffa.go 大白:call 雪子:call 雪子:call Psetname:call pdog:call在或者这样 pdog.PsetName("pdog.PsetName") (*pdog).Call()代码块如下:package main import "fmt" type Dog struct{ Name string } func (dog Dog)Call(){ fmt.Printf("%s:call\n",dog.Name) } func (dog Dog) Setname(name string){ dog.Name = name } func (dog *Dog) PsetName(name string) { dog.Name = name } func main(){ dog := Dog{"大白"} dog.Call() dog.Name = "雪子" dog.Call() dog.Setname("ss") dog.Call() (*&dog).PsetName("Psetname") dog.Call() pdog := &Dog{"pdog"} (*pdog).Call() }运行[root@linuxea.com /opt/Golang/work5]# go run ffa.go 大白:call 雪子:call 雪子:call Psetname:call pdog:call pdog.PsetName:call8.3命名方法嵌入以user和address为例package main import "fmt" type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr Address }如下:func (addr Address)Addr()string{ return fmt.Sprintf("%s-%s-%s-%s",addr.Region,addr.Street,addr.No,addr.Name) }user方法中,addr调用的是addr的方法,也就是上面写的这个方法func (user User)User()string{ return fmt.Sprintf("%d-%s-%s",user.ID,user.Name,user.Addr.Addr()) }而后我们调用func main(){ var u User = User{ ID:1, Name:"mark", Addr: Address{ Region:"北京市", Street:"烤鸭", No:"123", Name:"mark2", }, } fmt.Println(u) }代码块如下:package main import "fmt" type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr Address } func (addr Address)Addr()string{ return fmt.Sprintf("%s-%s-%s-%s",addr.Region,addr.Street,addr.No,addr.Name) } func (user User)User()string{ return fmt.Sprintf("%d-%s-%s",user.ID,user.Name,user.Addr.Addr()) } func main(){ var u User = User{ ID:1, Name:"mark", Addr: Address{ Region:"北京市", Street:"烤鸭", No:"123", Name:"mark2", }, } fmt.Println(u) }运行[root@linuxea.com /opt/Golang/work5]# go run mmqr.go {1 mark {北京市 烤鸭 123 mark2}}单独调用属性的方法fmt.Println(u.User()) fmt.Println(u.Addr.Addr())如下:[root@linuxea.com /opt/Golang/work5]# go run mmqr.go {1 mark {北京市 烤鸭 123 mark2}} 1-mark-北京市-烤鸭-123-mark2 北京市-烤鸭-123-mark28.3.1.String函数我们还可以将两种方法命名为String,在打印方法的时候,go会自动调用string方法返回字符串进行打印,如下:这个string方法是fmt.Println中调用的,print发现有这方法就进行调用,如果没有会将结构体属性并结成大括号的方式打印func (addr Address)String()string{ return fmt.Sprintf("%s-%s-%s-%s",addr.Region,addr.Street,addr.No,addr.Name) } func (user User)String()string{ return fmt.Sprintf("%d-%s-%s",user.ID,user.Name,user.Addr) }代码块如下:package main import "fmt" type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr Address } func (addr Address)String()string{ return fmt.Sprintf("%s-%s-%s-%s",addr.Region,addr.Street,addr.No,addr.Name) } func (user User)String()string{ return fmt.Sprintf("%d-%s-%s",user.ID,user.Name,user.Addr) } func main(){ var u User = User{ ID:1, Name:"mark", Addr: Address{ Region:"北京市", Street:"烤鸭", No:"123", Name:"mark2", }, } fmt.Println(u) fmt.Println(u.Addr) }如下:[root@linuxea.com /opt/Golang/work5]# go run mmqr1.go 1-mark-北京市-烤鸭-123-mark2 北京市-烤鸭-123-mark28.4匿名方法嵌入若结构体匿名嵌入带有方法的结构体时,则在外部结构体可以调用嵌入结构体的方法,并且在调用时只有嵌入的字段会传递给嵌入结构体方法的接收者。当被嵌入结构体与嵌入结构体据有相同名称的方法时,则使用对象.方法名调用被嵌入结构体方法。若想要调用嵌入结构体方法,则使用对象.嵌入结构体名.方法定义结构体中有id和name,分别定义get和set,set使用指针类型定义结构体Usertype User struct{ id int name string }getidfunc (user User)Getid() int { return user.id }getnamefunc (user User)Getname() string{ return user.name }setid,使用指针接收者func (user *User) SetID(id int){ user.id = id }setname,使用指针接收者func (user *User) Setname(name string){ user.name = name }而后我们在定义一个结构体嵌入Usertype Employee struct{ User Salary float64 }而后在main调用func main(){ var mm Employee =Employee{ User :{ id:1, name:"mark", }, Salary:10000.1, } }8.4.1通过方法获取如果此时获取user对象,就可以使用getname fmt.Println(mm.User.Getname())也可以写成这样 fmt.Println(mm.Getname())代码块如下:package main import "fmt" type User struct{ id int name string } func (user User)Getid() int { return user.id } func (user User)Getname() string{ return user.name } func (user *User) SetID(id int){ user.id = id } func (user *User) Setname(name string){ user.name = name } type Employee struct{ User Salary float64 } func main(){ var mm Employee =Employee{ User:User{ id:1, name:"mark", }, Salary:10000.1, } fmt.Println(mm.User.Getname()) fmt.Println(mm.Getname()) }如下:[root@linuxea.com /opt/Golang/work5]# go run nnqr3.go mark8.4.2通过方法修改这里的方法在上面已经定义并且使用指针 mm.Setname("marksugar") fmt.Println(mm.User.Getname())代码块package main import "fmt" type User struct{ id int name string } func (user User)Getid() int { return user.id } func (user User)Getname() string{ return user.name } func (user *User) SetID(id int){ user.id = id } func (user *User) Setname(name string){ user.name = name } type Employee struct{ User Salary float64 } func main(){ var mm Employee =Employee{ User:User{ id:1, name:"mark", }, Salary:10000.1, } fmt.Println(mm.User.Getname()) mm.Setname("marksugar") fmt.Println(mm.Getname()) }mm.Getname()与mm.User.Getname()是一样的,getname自动解引用,这里是函数前的参数-接收者值或者指针调用,在go中中山自动转换,这种方式就是解引用和取引用,并且解引用和取引用只会发生在接收者这块运行[root@linuxea.com /opt/Golang/work5]# go run nnqr3.go mark marksugar演变下假设Employee结构体中加上name,如下type Employee struct{ User Salary float64 name string }使用Getname调用是否为空?func main(){ var mm Employee =Employee{ User:User{ id:1, name:"mark", }, Salary:10000.1, } fmt.Println(mm.User.Getname()) mm.Setname("marksugar") fmt.Println(mm.Getname()) fmt.Println(mm.name) }运行[root@linuxea.com /opt/Golang/work5]# go run nnqr3.go mark marksugar : 只有在使用mm.name调用的时候才会是空的,使用Getname方法调用的时候,实际上调用的是User本身的name。但是当使用Getname的时候,Employee是空的,就会找到User中的name我们在定义一个Employee的方法,名称也是Getname,如下:func (employee Employee)Getname()string{ return employee.name }并且初始化name:"justin" var mm Employee =Employee{ User:User{ id:1, name:"mark", }, Salary:10000.1, name:"justin", }而后在进行访问 fmt.Println(mm.User.Getname()) fmt.Println(mm.Getname()) mm.Setname("marksugar") fmt.Println(mm.Getname()) fmt.Println(mm.name)代码块如下:package main import "fmt" type User struct{ id int name string } func (user User)Getid() int { return user.id } func (user User)Getname() string{ return user.name } func (user *User) SetID(id int){ user.id = id } func (user *User) Setname(name string){ user.name = name } type Employee struct{ User Salary float64 name string } func (employee Employee)Getname()string{ return employee.name } func main(){ var mm Employee =Employee{ User:User{ id:1, name:"mark", }, Salary:10000.1, name:"justin", } fmt.Println(mm.User.Getname()) fmt.Println(mm.Getname()) mm.Setname("marksugar") fmt.Println(mm.Getname()) fmt.Println(mm.name) }运行[root@linuxea.com /opt/Golang/work5]# go run nnqr3.go mark justin justin justin如上结果中,mm.User.Getname()是调用的是User的Getname,而mm.Getname()调用的是Employee的Getname,而Setname也是User的Setname,打印mm.Getname()就只会是justin了那我们在写一个方法是Employee的Setnamefunc (employee *Employee) Setname(){ employee.name = name }其他不变,代码块如下:package main import "fmt" type User struct{ id int name string } func (user User)Getid() int { return user.id } func (user User)Getname() string{ return user.name } func (user *User) SetID(id int){ user.id = id } func (user *User) Setname(name string){ user.name = name } type Employee struct{ User Salary float64 name string } func (employee Employee)Getname()string{ return employee.name } func (employee *Employee) Setname(name string){ employee.name = name } func main(){ var mm Employee =Employee{ User:User{ id:1, name:"mark", }, Salary:10000.1, name:"justin", } fmt.Println(mm.User.Getname()) fmt.Println(mm.Getname()) mm.Setname("marksugar") fmt.Println(mm.Getname()) fmt.Println(mm.name) }运行[root@linuxea.com /opt/Golang/work5]# go run nnqr3.go mark justin marksugar marksugar那么现在,mm.Getname()获取的就是Employee的Getname,mm.Setname("marksugar")修改的也是Employee的Setname的name这便是匿名结构体方法的调用。8.5方法值和方法表达式方法值/方法表达式: 方法也可以赋值给变量,存储在数组,切片,映射中,也可以作为参数传递给函数,也可以作为返回值进行返回。方法有两种,一种使用对象/对象指针调用的方法值。另外一种是有类型/类型调用的方法表达式。8.5.1方法值示例我们定义一个dog的结构体type Dog struct{ name string }在定义一个Call方法func (dog Dog) Call(){ fmt.Printf("%s:wangwang\n",dog.name) }在定义一个setname修改func (dog *Dog) Setname(name string){ dog.name = name }我们可将dog方法赋值给一个变量func main(){ dog := Dog{"二狗"} gg := dog.Call fmt.Printf("%T:\n",gg) gg() }运行[root@linuxea.com /opt/Golang/work5]# go run dog.go func(): 二狗:wangwang我们使用setname修改dog.Setname("三狗")如下:func main(){ dog := Dog{"二狗"} gg := dog.Call dog.Setname("三狗") fmt.Printf("%T:\n",gg) gg() dog.Setname("三狗") gg1 := dog.Call gg1() }这里必须重新赋值dog.Call到gg1 dog.Setname("三狗") gg1 := dog.Call gg1()因为在gg := dog.Call中赋值后dog.Call已经复制到gg中,gg是值类型,setname后如果直接使用gg()是使用之前的,并且不会发生改变的。这里需要使用dog.Call重新赋值给gg1而后调用如果多次调用修改gg或者gg1,是不会影响到方法值的。值接收者方法会将对象进行拷贝运行[root@linuxea.com /opt/Golang/work5]# go run dog.go func(): 二狗:wangwang 三狗:wangwang8.5.2方法值指针如果不是用指针,是这样package main import "fmt" type Dog struct{ name string } func (dog Dog) Call(){ fmt.Printf("%s:wangwang\n",dog.name) } func (dog *Dog) Setname(name string){ dog.name = name } func main(){ dog := Dog{"二狗"} gg := dog.Call fmt.Printf("%T:\n",gg) gg() dog.Setname("三狗") dog.Call() gg() }运行[root@linuxea.com /opt/Golang/work5]# go run dog.go func(): 二狗:wangwang 三狗:wangwang 二狗:wangwang但是,如果是指针方法,就会不一样了,如下:func (dog *Dog) Call(){ fmt.Printf("%s:wangwang\n",dog.name) } func (dog *Dog) Setname(name string){ dog.name = name }指针就会自动取引用调用的方式我们可以这样func main(){ dog := Dog{"二狗"} gg := dog.Call fmt.Printf("%T:\n",gg) gg() dog.Setname("三狗") dog.Call() gg() }代码块package main import "fmt" type Dog struct{ name string } func (dog *Dog) Call(){ fmt.Printf("%s:wangwang\n",dog.name) } func (dog *Dog) Setname(name string){ dog.name = name } func main(){ dog := Dog{"二狗"} gg := dog.Call fmt.Printf("%T:\n",gg) gg() dog.Setname("三狗") dog.Call() gg() }运行[root@linuxea.com /opt/Golang/work5]# go run dog.go func(): 二狗:wangwang 三狗:wangwang 三狗:wangwang由此可见,我们使用了指针后,gg的值也变成了三狗:wangwang.见上述代码8.5.3方法表达式还是以上述的示例,如下package main import "fmt" type Dog struct { name string } func (dog Dog) Call(){ fmt.Printf("%s:旺旺\n",dog.name) } func (dog *Dog) Setname(name string){ dog.name = name }方法表达式就是用结构体的名字去访问对象,如下func main(){ m1 := Dog.Call m2 := (*Dog).Setname fmt.Printf("%T\n",m1) fmt.Printf("%T\n",m2) }运行[root@linuxea.com /opt/Golang/work5]# go run ffbds.go func(main.Dog) func(*main.Dog, string)对于方法表达式来说,调用的时候,必须传递一个对象进去 dog := Dog("小灰") m1(dog)运行[root@linuxea.com /opt/Golang/work5]# go run ffbds.go func(main.Dog) func(*main.Dog, string) 小灰:旺旺setname使用setname修改名称。我们赋值m2,如下:m2 = (*Dog).Setname m2(&dog,"小黑") m1(dog)如下package main import "fmt" type Dog struct { name string } func (dog Dog) Call(){ fmt.Printf("%s:旺旺\n",dog.name) } func (dog *Dog) Setname(name string){ dog.name = name } func main(){ m1 := Dog.Call m2 := (*Dog).Setname fmt.Printf("%T\n",m1) fmt.Printf("%T\n",m2) dog := Dog{"小灰"} m1(dog) m2 = (*Dog).Setname m2(&dog,"小黑") m1(dog) }运行[root@linuxea.com /opt/Golang/work5]# go run ffbds.go func(main.Dog) func(*main.Dog, string) 小灰:旺旺 小黑:旺旺值对象可以将指针的方法赋值给一个变量,但定义的是指针接收者就不能用值对象调用。这是因为 go会自动生成一个根据值接收者方法会生成一个指针接收者方法。如下package main import "fmt" type Dog struct { name string } func (dog Dog) Call(){ fmt.Printf("%s:在叫\n",dog.name) } func main(){ m1 := (*Dog).Call dog := Dog{"小黄"} m1(&dog) }也可以写成这样(*Dog).Call(&Dog{"小黄"})运行[root@linuxea.com /opt/Golang/work5]# go run ff1.go 小黄:在叫
2020年12月17日
2,700 阅读
0 评论
0 点赞
2020-12-14
linuxea:go匿名结构体和指针(39)
匿名结构体,顾名思义,就是没有名称的,也是只需要使用一次的。或者是函数内的,比如配置,web开发渲染模板时候使用。3.匿名结构体匿名结构体会在内部声明一个和当前类型相同名称的属性名。在访问的时候可以使用变量名.属性名访问定义现在,我们定义一个me的匿名结构体 var me struct { ID int Name string }简短声明 me := struct { ID int Name string }如下:package main import "fmt" func main(){ var me struct { ID int Name string } fmt.Printf("%T\n",me) fmt.Printf("%#v\n",me) }运行[root@linuxea.com /opt/Golang/work5]# go run nm.go struct { ID int; Name string } struct { ID int; Name string }{ID:0, Name:""}3.1匿名结构体的访问和修改我们可以直接使用匿名结构体的变量名.属性名即可进行访问和修改。大致如下: me.ID = 1 me.Name = "mark" fmt.Println(me.ID,me.Name) fmt.Printf("%#v\n",me)如下:package main import "fmt" func main(){ var me struct { ID int Name string } fmt.Printf("%T\n",me) fmt.Printf("%#v\n",me) me.ID = 1 me.Name = "mark" fmt.Println(me.ID,me.Name) fmt.Printf("%#v\n",me) }运行[root@linuxea.com /opt/Golang/work5]# go run nm.go struct { ID int; Name string } struct { ID int; Name string }{ID:0, Name:""} 1 mark struct { ID int; Name string }{ID:1, Name:"mark"}4.结构体的组合一个结构体内的属性是另外一个结构体类型的,我们来了解结构体的命名嵌入。示例1我们在购物平台购物填写地址的时候,一般会有很多的选况,我们简单用代码设置下:.创建一个Address,其中包含了地址的属性信息type Address struct { Region string Street string No string }而后,创建 一个User的struct,在Addr的属性上填写上面结构体的名称Addresstype User struct { ID int Name string Addr Address }那么在声明传递的时候和单个结构体是不一样的。因为在结构体中addr的属性是另外一个结构体,那么我们可以先定义一个变量来接收address。如下:addr := Address{Region: "上海市",Street:"徐汇区",No:"1501"}而后在将addr放到User赋值的结构体变量中,如下:user := User{ ID: 1, Name: "mark", Addr: addr, }示例2以上面例子为例,我们可以直接在定义结构体变量的时候直接就Addr调用Address{}配置,如下: user := User{ ID:1, Name:"mark", Addr:Address{ Region: "上海市", Street:"徐汇区", No:"1501" } }如下:package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } func main(){ user := User{ ID:1, Name:"mark", Addr:Address{ Region: "上海市", Street:"徐汇区", No:"1501", }, } fmt.Printf("%#v\n",user) }运行[root@linuxea.com /opt/Golang/work5]# go run zh1.go main.User{ID:1, Name:"mark", Addr:main.Address{Region:"上海市", Street:"徐汇区", No:"1501"}}假如现在要访问或者修改Address的Region,只需要 纵深即可,如user.Addr.Region: fmt.Println(user.Addr.Region) user.Addr.Region = "北京" fmt.Println(user.Addr.Region)运行[root@linuxea.com /opt/Golang/work5]# go run zh1.go main.User{ID:1, Name:"mark", Addr:main.Address{Region:"上海市", Street:"徐汇区", No:"1501"}} 上海市 北京5.结构体匿名嵌入假设现在建立一个员工的的对象,其中包含,id,name,addr,salary,如下:type Employee struct{ ID int Name string Addr Address Salary float64 }但是已有的结构体如下,如下:type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address }那么这个时候,就可以在Employee结构体中组合User,命名为user,如下:type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ user User Salary float64 }这样一来,Employee中就组合了两个结构体。但是在Employee的结构体中,user是 User命名的,但是可以不需要写user的,如果不写就是匿名嵌入,如下:type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ User Salary float64 }如果使用了匿名结构体,如User,在初始化的时候就可以使用User属性进行初始化,如下:package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ User Salary float64 } func main(){ me := Employee{} fmt.Printf("%#v\n",me) }运行[root@linuxea.com /opt/Golang/work5]# go run anonymouns.go main.Employee{User:main.User{ID:0, Name:"", Addr:main.Address{Region:"", Street:"", No:""}}, Salary:0}匿名结构体会通过类名自己创建属性假如此刻用字面量初始化一个属性就可以 这样来初始化,如下: me02 := Employee{ User: User{ ID:1, Name: "mark", Addr:Address{ Region:"上海市", Street:"徐汇区", ID:10, }, }, Salary: 10023.3, }亦或者如下 me.Salary = 1.78 me.Name = "mark" me.Addr.Region = "上海市" fmt.Printf("%#v\n",me)我么使用第一种方式,如下package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ User Salary float64 } func main(){ me := Employee{} fmt.Printf("%#v\n",me) me02 := Employee{ User: User{ ID:1, Name: "mark", Addr:Address{ Region:"上海市", Street:"徐汇区", No:"10501", }, }, Salary: 10023.3, } fmt.Printf("%#v\n",me02) }运行[root@linuxea.com /opt/Golang/work5]# go run anonymouns1.go main.Employee{User:main.User{ID:0, Name:"", Addr:main.Address{Region:"", Street:"", No:""}}, Salary:0} main.Employee{User:main.User{ID:1, Name:"mark", Addr:main.Address{Region:"上海市", Street:"徐汇区", No:"10501"}}, Salary:10023.3}我们可以访问结构体中的某个,如下:这里需要注意到是,使用User: User{},那么在访问数据的时候会可以加上User,也可以不要fmt.Println(me02.User.ID) fmt.Println(me02.User.Addr.Region) fmt.Println(me02.Salary) fmt.Println(me02.Name) fmt.Println(me02.Addr.Street) fmt.Println(me02.Salary)运行[root@linuxea.com /opt/Golang/work5]# go run anonymouns1.go main.Employee{User:main.User{ID:0, Name:"", Addr:main.Address{Region:"", Street:"", No:""}}, Salary:0} main.Employee{User:main.User{ID:1, Name:"mark", Addr:main.Address{Region:"上海市", Street:"徐汇区", No:"10501"}}, Salary:10023.3} mark 上海市 10023.3 mark 徐汇区 10023.35.1匿名结构体属性名重复的操作那么,现在。有这样一个问题。如下:type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ User Salary float64 Name string }以上中,在Employee中的name和User中的name,此刻如果进行访问使用的会是那个?package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ User Salary float64 Name string } func main(){ me02 := Employee{ User: User{ ID:1, Name: "mark", Addr:Address{ Region:"上海市", Street:"徐汇区", No:"10", }, }, Salary: 10023.3, } fmt.Printf("%#v\n",me02) }运行[root@linuxea.com /opt/Golang/work5]# go run ff.go main.Employee{User:main.User{ID:1, Name:"mark", Addr:main.Address{Region:"上海市", Street:"徐汇区", No:"10"}}, Salary:10023.3, Name:""} me02.Name: me02.Name: 结果为空。我们重新赋值,使用me02.Name = "sean" me02.Name = "sean" fmt.Println("me02.Name:",me02.Name)运行[root@linuxea.com /opt/Golang/work5]# go run ff.go main.Employee{User:main.User{ID:1, Name:"mark", Addr:main.Address{Region:"上海市", Street:"徐汇区", No:"10"}}, Salary:10023.3, Name:""} me02.Name: me02.Name: sean现在就可以访问到。当组合中的结构体有相同属性的是,会先访问到当前结构体的属性名,如果没有就会到组合结构体或者匿名结构体中找。如果匿名结构体和当前结构体都有相同的属性名,在访问的时候就需要指定匿名结构体的具体属性名。示例如下:为了具体示例,先给当前结构体赋值,并打印当前Employee中的Name me02.Name = "sean" fmt.Println("me02.Name:",me02.Name)而后访问匿名结构体中的嵌入的属性名User下的Name fmt.Println("me02.Name:",me02.User.Name)代码块:package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ User Salary float64 Name string } func main(){ me02 := Employee{ User: User{ ID:1, Name: "mark", Addr:Address{ Region:"上海市", Street:"徐汇区", No:"10", }, }, Salary: 10023.3, } fmt.Printf("%#v\n",me02) fmt.Println("me02.Name:",me02.Name) me02.Name = "sean" fmt.Println("me02.Name:",me02.Name) fmt.Println("me02.Name:",me02.User.Name) }运行[root@linuxea.com /opt/Golang/work5]# go run ff.go main.Employee{User:main.User{ID:1, Name:"mark", Addr:main.Address{Region:"上海市", Street:"徐汇区", No:"10"}}, Salary:10023.3, Name:""} me02.Name: me02.Name: sean me02.Name: mark一般而言,我们使用全路径写法,即是me02.User.Name写法。示例倘若在结构体的组合有重复的属性名,就需要使用全路径写法,如下type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr Address } type Employee struct{ User Salary float64 Name string }现在就需要进行全路径才能够赋值和获取,代码块如下:package main import "fmt" type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr Address } type Employee struct{ User Salary float64 Name string } func main(){ me02 := Employee{ User: User{ ID:1, Name: "mark", Addr:Address{ Region:"上海市", Street:"徐汇区", No:"10", Name: "mark3", }, }, Salary: 10023.3, Name: "mark2", } fmt.Printf("%#v\n",me02) me02.User.Name = "sean" fmt.Println("me02.Name:",me02.User.Name) me02.Addr.Name = "sean1" fmt.Println("me02.Name:",me02.Addr.Name) me02.Name = "sean2" fmt.Println("me02.Name:",me02.Name) }运行[root@linuxea.com /opt/Golang/work5]# go run ql.go main.Employee{User:main.User{ID:1, Name:"mark", Addr:main.Address{Region:"上海市", Street:"徐汇区", No:"10", Name:"mark3"}}, Salary:10023.3, Name:"mark2"} me02.Name: sean me02.Name: sean1 me02.Name: sean2这样似乎不太明显,在看另外一个示例示例嵌入的两个匿名结构体和匿名结构体中的冲突使用方式,结构体如下:type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr Address } type Employee struct{ User Address Salary float64 Name string }如下:package main import "fmt" type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr Address } type Employee struct{ User Address Salary float64 Name string } func main(){ var me Employee fmt.Printf("%T,%#v\n",me,me) me.User.Name = "mark" me.Address.Name = "mark2" me.Name = "mark3" me.User.Addr.Name = "mark4" fmt.Println(me.User.Name) fmt.Println(me.Address.Name) fmt.Println(me.Name) fmt.Println(me.User.Addr.Name) fmt.Printf("%#v\n",me) }运行[root@linuxea.com /opt/Golang/work5]# go run q2.go main.Employee,main.Employee{User:main.User{ID:0, Name:"", Addr:main.Address{Region:"", Street:"", No:"", Name:""}}, Address:main.Address{Region:"", Street:"", No:"", Name:""}, Salary:0, Name:""} mark mark2 mark3 mark4 main.Employee{User:main.User{ID:0, Name:"mark", Addr:main.Address{Region:"", Street:"", No:"", Name:"mark4"}}, Address:main.Address{Region:"", Street:"", No:"", Name:"mark2"}, Salary:0, Name:"mark3"}6.结构体指针6.1 结构体指针命名嵌入如下,在User中命名嵌入了Address,但是使用的是指针类型的嵌入package main import "fmt" type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr *Address }如果是指针类型,那么User的零值就是nilfunc main(){ var mm User fmt.Printf("%#v\n",mm) }初始化与其他方式一样,不通的是在Address上需要使用指针方式 mm = User{ ID:1, Name: "mark", Addr:&Address{ Region: "上海市", Street:"淞虹路", No:"12362", Name:"MarkSugar", }, } fmt.Printf("%#v\n",)代码块如下:[root@linuxea.com /opt/Golang/work5]# cat proint.go package main import "fmt" type Address struct { Region string Street string No string Name string } type User struct { ID int Name string Addr *Address } func main(){ var mm User fmt.Printf("%#v\n",mm) mm = User{ ID:1, Name: "mark", Addr:&Address{ Region: "上海市", Street:"淞虹路", No:"12362", Name:"MarkSugar", }, } fmt.Printf("%#v\n",mm) }运行[root@linuxea.com /opt/Golang/work5]# go run proint.go main.User{ID:0, Name:"", Addr:(*main.Address)(nil)} main.User{ID:1, Name:"mark", Addr:(*main.Address)(0xc000084040)}6.2.结构体指针匿名嵌入当在结构体嵌入的时候,直接使用的是指针类型的,就没有属性名了type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ *User Salary float64 }如下:func main(){ var me Employee fmt.Printf("%#v\n",me) me = Employee{ Salary: 1.5, User: &User{ ID:1, Name:"mark", Addr:Address{ Region:"北京市", Street:"望京", }, }, } fmt.Printf("%#v\n",me) }如下:package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } type Employee struct{ *User Salary float64 } func main(){ var me Employee fmt.Printf("%#v\n",me) me = Employee{ Salary: 1.5, User: &User{ ID:1, Name:"mark", Addr:Address{ Region:"北京市", Street:"望京", }, }, } fmt.Printf("%#v\n",me) fmt.Println(me.User.Name) fmt.Println(me.User.Addr) fmt.Println(me.User.Addr.Region) }运行[root@linuxea.com /opt/Golang/work5]# go run nmqr.go main.Employee{User:(*main.User)(nil), Salary:0} main.Employee{User:(*main.User)(0xc00008e000), Salary:1.5} mark {北京市 望京 } 北京市值类型和引用类型值类型是不会变,引用类型如下:和此前值类型一样,me赋值 后,然后赋值到me2,而后修改me2,并没有影响到me值,同样change修改了u.Name,也对me2没有影响package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } func change(u User){ u.Name = "abc" } func main(){ me := User{} me2 := me me2.Name = "mark" fmt.Printf("%#v\n",me) fmt.Printf("%#v\n",me2) change(me2) fmt.Printf("%#v\n",me2) }运行[root@linuxea.com /opt/Golang/work5]# go run z.go main.User{ID:0, Name:"", Addr:main.Address{Region:"", Street:"", No:""}} main.User{ID:0, Name:"mark", Addr:main.Address{Region:"", Street:"", No:""}} main.User{ID:0, Name:"mark", Addr:main.Address{Region:"", Street:"", No:""}}如果此时传递的是地址进去,就会发生改变,如下:func changepoint(u *User){ u.Name = "sean" }如下:package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr Address } func change(u User){ u.Name = "abc" } func changepoint(u *User){ u.Name = "sean" } func main(){ me := User{} me2 := me me2.Name = "mark" fmt.Printf("%#v\n",me) fmt.Printf("%#v\n",me2) change(me2) fmt.Printf("%#v\n",me2) changepoint(&me2) fmt.Printf("%#v\n",me2) }运行[root@linuxea.com /opt/Golang/work5]# go run z.go main.User{ID:0, Name:"", Addr:main.Address{Region:"", Street:"", No:""}} main.User{ID:0, Name:"mark", Addr:main.Address{Region:"", Street:"", No:""}} main.User{ID:0, Name:"mark", Addr:main.Address{Region:"", Street:"", No:""}} main.User{ID:0, Name:"sean", Addr:main.Address{Region:"", Street:"", No:""}}如果此时Address是指针类型,那么结果就不一样了type Address struct { Region string Street string No string } type User struct { ID int Name string Addr *Address }我们首先初始化me,而后用me2重新修改me2.Addr.Region = "上海市".func main(){ me := User{ ID:1, Name:"mark", Addr:&Address{ Region:"北京", Street:"大同", No:"1", }, } me2 := me me2.Name = "mark" me2.Addr.Region = "上海市" fmt.Printf("%#v\n",me.Addr) fmt.Printf("%#v\n",me2.Addr) }如下package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr *Address } func main(){ me := User{ ID:1, Name:"mark", Addr:&Address{ Region:"北京", Street:"大同", No:"1", }, } me2 := me me2.Name = "mark" me2.Addr.Region = "上海市" fmt.Printf("%#v\n",me.Addr) fmt.Printf("%#v\n",me2.Addr) }运行[root@linuxea.com /opt/Golang/work5]# go run zz.go &main.Address{Region:"上海市", Street:"大同", No:"1"} &main.Address{Region:"上海市", Street:"大同", No:"1"}结果可见指针已经修改了6.3New函数对于结构体,我们可以尝试使用new函数来创建,这样别人就可以通过调用函数的方式来返回一个对象。func NewUser(id int,name string,region,street,no string)User{ return User{ ID:id, Name:name, Addr: &Address{region,street,no}, } }在main中调用即可func main(){ NewUser(1,"mark","上海市","淞虹路","100") }如下:package main import "fmt" type Address struct { Region string Street string No string } type User struct { ID int Name string Addr *Address } func NewUser(id int,name string,region,street,no string)User{ return User{ ID:id, Name:name, Addr: &Address{region,street,no}, } } func main(){ me := NewUser(1,"mark","上海市","淞虹路","100") fmt.Printf("%#v\n",me) }运行[root@linuxea.com /opt/Golang/work5]# go run z1.go main.User{ID:1, Name:"mark", Addr:(*main.Address)(0xc000062150)}7.结构体可见性结构体首先字母大写则包外可见,否则仅包内可访问。结构体属性名首字母大写包外可见,否则仅包内可访问。总结:结构体和属性名首字母大写才能包外访问。否则就不能够在包外访问。
2020年12月14日
3,197 阅读
0 评论
0 点赞
2020-12-12
linuxea:go结构体简单用法(38)
结构体是由一系列属性组成的复合数据类型,每个属性都具有名称,类型,结构体将属性组合在一起由程序进行处理1.结构体定义自定义类型在go语言中使用type声明一种新的类型,语法格式如下:type Typename Formatter某些时候我们想表示某种类型具体的含义,就可以定义一个自己的类型。尤为重要的是,当你使用type声明了类型之后,在定义的类型将不是同一个类型,比如:type num int var num1 intnum和num1不是同一个类型。如果要进行运算,需要转换。1.1定义类型示例一通常我们定义一个变量, 如:age,表示年龄的时候,一般使用var 直接定义,如下var Age int但是,这样并不能体现出age的含义,那就可以定义一个type Age inttype Age int而后在定义变量就成了这样var Age Age 如下package main import ( "fmt" ) type Age int func main(){ var Age Age fmt.Println(Age) }运行[root@linuxea.com /opt/Golang/work5]# go run type.go 0我们可以进行赋值或者计算Age += 18如下:package main import ( "fmt" ) type Age int func main(){ var Age Age Age += 18 fmt.Println(Age) }运行[root@linuxea.com /opt/Golang/work5]# go run type.go 18示例二定义个User,格式是string类型type User map[string]string如下:package main import ( "fmt" ) type User map[string]string func main(){ me := make(User) me["addr"] = "Beijing" fmt.Println(me) fmt.Printf("%T\n",me) }运行[root@linuxea.com /opt/Golang/work5]# go run user.go map[addr:Beijing] main.User示例三定义一个匿名函数类型type Callback func(...string)如下:package main import ( "fmt" ) type Callback func(...string) func main(){ var list Callback = func(args ...string){ for i,v := range args{ fmt.Println(i,":",v) } } list("a","b","c") }运行[root@linuxea.com /opt/Golang/work5]# go run callback.go 0 : a 1 : b 2 : c假如现在要定义一个结构,就需要结构体1.2定义结构体假设现在定义一个用户的结构体,要声明就需要使用struct模式进行定义,模式就可以认为是属性,比如,用户就需要有id属性,name,生日等。结构体的零值就是结构体内的类型的零值示例定义User的结构体type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string }而后var定义变量,类型即可var user User如下:使用%#v打印出类型package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ var user User fmt.Println(user) fmt.Printf("%#v",user) }运行[root@linuxea.com /opt/Golang/work5]# go run struct.go {0 0001-01-01 00:00:00 +0000 UTC } main.User{ID:0, Name:"", Birthdy:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, Addr:"", Tel:"", Remark:""}初始化结构体1我们可以对这些进行初始化赋值这种方式的初始化,需要对每个值进行赋值,通过定义的顺序进行赋值。 var user2 User{1,"mark",time.Now(),"北京市","10010","mark"}代码块package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ var user User fmt.Println(user) fmt.Printf("%#v",user) var user2 User = User{1,"mark",time.Now(),"北京市","10010","mark"} fmt.Println(user2) fmt.Printf("%#v",user2) }运行[root@linuxea.com /opt/Golang/work5]# go run struct.go {0 0001-01-01 00:00:00 +0000 UTC } main.User{ID:0, Name:"", Birthdy:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, Addr:"", Tel:"", Remark:""}{1 mark 2019-10-04 17:28:24.492833938 +0800 CST m=+0.000264968 北京市 10010 mark} main.User{ID:1, Name:"mark", Birthdy:time.Time{wall:0xbf5de20e1d600c92, ext:264968, loc:(*time.Location)(0x56a0c0)}, Addr:"北京市", Tel:"10010", Remark:"mark"}我们可以对单个属性进行调用 fmt.Println(user4.Name)初始化结构体2零值如果要显示使用的是零值就可以什么都不传递进行配置var user3 User = User{} fmt.Println(user3)package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ var user3 User = User{} fmt.Println(user3) }运行[root@linuxea.com /opt/Golang/work5]# go run struct.go main.User{ID:1, Name:"mark", Birthdy:time.Time{wall:0xbf5de2823a31218c, ext:494037, loc:(*time.Location)(0x56a0c0)}, Addr:"北京市", Tel:"10010", Remark:"mark"}{0 0001-01-01 00:00:00 +0000 UTC }我们可以对单个属性进行调用 fmt.Println(user4.Name)初始化结构体3指定属性名的方式进行赋值,如下:使用属性名进行赋值就可以不用按照顺序赋值,并且可以省略一些不用的赋值,比如省略掉Remark:"mark"尤为注意的是,这里括号内的{}的每一行都需要,号 var user4 User = User{ ID:1, Name:"mark", Birthdy:time.Now(), Addr:"上海", Tel:"10086", }我们可以对单个属性进行调用 fmt.Println(user4.Name)如下:package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ var user4 User = User{ ID:1, Name:"mark", Birthdy:time.Now(), Addr:"上海", Tel:"10086", } fmt.Println(user4) fmt.Printf("%#v\n",user4) fmt.Println(user4.Name) }运行{1 mark 2019-10-04 17:55:22.37708593 +0800 CST m=+0.000061322 上海 10086 } main.User{ID:1, Name:"mark", Birthdy:time.Time{wall:0xbf5de3a29679dfea, ext:61322, loc:(*time.Location)(0x56a0c0)}, Addr:"上海", Tel:"10086", Remark:""} mark1.3定义结构体指针我们可以使用指针给结构体传值,假设结构体如下:type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string }指针只需要直接使用*即可var pointer *User也可以直接进行赋值,为此定义user4 var user4 User = User{ ID:1, Name:"mark", Birthdy:time.Now(), Addr:"上海", Tel:"10086", }而后使用指针赋值给*Uservar pointer *User = &user4代码块如下package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ var user4 User = User{ ID:1, Name:"mark", Birthdy:time.Now(), Addr:"上海", Tel:"10086", } var pointer *User = &user4 fmt.Println(pointer) }运行[root@linuxea.com /opt/Golang/work5]# go run pointer.go &{1 mark 2019-10-04 21:51:13.684714251 +0800 CST m=+0.000136163 上海 10086 }传空值传递控制大致可以如下即可package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ var pointer1 *User = &User{} fmt.Println(pointer1) fmt.Printf("%#v",pointer1) }运行[root@linuxea.com /opt/Golang/work5]# go run pointer1.go &{0 0001-01-01 00:00:00 +0000 UTC } &main.User{ID:0, Name:"", Birthdy:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, Addr:"", Tel:"", Remark:""}也可以使用new,比如:new出来的都是指针类型,一般用于结构体指针,而在切片和映射本身就是引用类型,一般不会使用new,而是makepackage main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ var pointer1 *User = new(User) fmt.Println(pointer1) fmt.Printf("%#v",pointer1) }运行[root@linuxea.com /opt/Golang/work5]# go run pointer2.go &{0 0001-01-01 00:00:00 +0000 UTC } &main.User{ID:0, Name:"", Birthdy:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, Addr:"", Tel:"", Remark:""}2.结构体操作结构体的获取和修改,我们只需要使用赋值的变量名.属性名即可。而修改直接重新赋值即可。2.1获取定义了结构体后,如何通过变量访问里面的属性呢?,如下package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ user4 := User{ ID:1, Name:"mark", Birthdy:time.Now(), Addr:"上海", Tel:"10086", } }此刻,我们访问一个属性,直接可以使用变量名.属性名即可,如下:比如只单单获取id和namefmt.Println(user4.ID,user4.Name)如下:package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ user4 := User{ ID:1, Name:"mark", Birthdy:time.Now(), Addr:"上海", Tel:"10086", } fmt.Println(user4.ID,user4.Name) }运行[root@linuxea.com /opt/Golang/work5]# go run struct2.go 1 mark2.2修改比如,我们直接修改teluser4.Tel = "1008600"代码块[root@linuxea.com /opt/Golang/work5]# cat struct2.go package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ user4 := User{ ID:1, Name:"mark", Birthdy:time.Now(), Addr:"上海", Tel:"10086", } fmt.Println(user4.ID,user4.Name,user4.Tel) user4.Tel = "1008600" fmt.Println(user4.ID,user4.Name,user4.Tel) }运行[root@linuxea.com /opt/Golang/work5]# go run struct2.go 1 mark 10086 1 mark 10086002.3指针结构体的修改我们直接使用上面的赋值修改即可 user := &User{ ID:2, Name: "feeker", }修改,这里用到*来进行解引用,如下 (*user).Name = "UZI" (*user).Tel = "10010"如下:package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ user := &User{ ID:2, Name: "feeker", } (*user).Name = "UZI" (*user).Tel = "10010" fmt.Printf("%#v",user) }运行[root@linuxea.com /opt/Golang/work5]# go run struct3.go &main.User{ID:2, Name:"UZI", Birthdy:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, Addr:"", Tel:"10010", Remark:""}2.4指针结构的获取指针结构体在访问属性的时候,可以直接使用变量名.属性名来进行访问。 user.Addr = "beijing" fmt.Printf("%#v\n",user)user.Addr = "beijing" 事实上也进行了解应用操作如下:package main import ( "fmt" "time" ) type User struct { ID int Name string Birthdy time.Time Addr string Tel string Remark string } func main(){ user := &User{ ID:2, Name: "feeker", } (*user).Name = "UZI" (*user).Tel = "10010" fmt.Printf("%#v\n",user) user.Addr = "beijing" fmt.Printf("%#v\n",user) }运行[root@linuxea.com /opt/Golang/work5]# go run struct3.go &main.User{ID:2, Name:"UZI", Birthdy:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, Addr:"", Tel:"10010", Remark:""} &main.User{ID:2, Name:"UZI", Birthdy:time.Time{wall:0x0, ext:0, loc:(*time.Location)(nil)}, Addr:"beijing", Tel:"10010", Remark:""}
2020年12月12日
2,719 阅读
0 评论
0 点赞
2020-12-11
linuxea:go os.args/time/md5/base/log包简单使用(37)
os.args模块和time,md5以及base和log模块9.os.args模块os.args是在os模块中,我们可以简单打印os.args,而后传递 一些参数package main import ( "os" "fmt" ) func main(){ fmt.Println(os.Args) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run args.go www.linuxea.com [/tmp/go-build909504842/b001/exe/args www.linuxea.com]打印的结果是,文件的目录和传入的参数也可以进行build[root@linuxea.com /opt/Golang/work4/stdpkg]# go build args.go [root@linuxea.com /opt/Golang/work4/stdpkg]# chmod +x args如下:[root@linuxea.com /opt/Golang/work4/stdpkg]# ./args www.linuxea.com [./args www.linuxea.com]命令后传递参数可以看flag10.flag模块绑定变量示例我们定义一个flag的参数传递首先定义个变量var port int而后使用flag.IntVar()绑定命令行参数,这里需要传递指针,参数,默认值,备注。如下:参数-P默认值88备注nginx portflag.IntVar(&port,"P",88,"nginx port")解析命令行参数flag.Parse()而后打印fmt.Println(port)在如法炮制一个host的string和verbor的布尔类型参数,如下package main import ( "flag" "fmt" ) func main(){ var port int var host string var verbor bool flag.IntVar(&port,"P",88,"nginx port") flag.StringVar(&host,"H","127.0.0.1","-host addr") flag.BoolVar(&verbor,"v",false,"detail log") flag.Parse() fmt.Println(host,port,verbor) }运行默认的参数就是127.0.0.1 88[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go -P 66 -H 10.0.0.96 10.0.0.96 66 false我们可以传递参数,-P和-H,-P是int类型,-H是string类型,-V是bool类型,如果输入错误就会报错,并且打出使用信息[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go -P st -H 10.0.0.96 -v invalid value "st" for flag -P: parse error Usage of /tmp/go-build440964329/b001/exe/flag: -H string -host addr (default "127.0.0.1") -P int nginx port (default 88) -v detail log exit status 2使用-P和-H传递参数,如果不加-v默认就是false[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go -P 66 -H 10.0.0.96 10.0.0.96 66 false加上-V就变成了true[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go -P 66 -H 10.0.0.96 -v 10.0.0.96 66 true10.1--help利用boolvar编写help帮助声明一个Boolvar的help变量var help bool flag.BoolVar(&help,"help",false,"help")func main(){ var port int var host string var verbor bool var help bool flag.IntVar(&port,"P",88,"nginx port") flag.StringVar(&host,"H","127.0.0.1","-host addr") flag.BoolVar(&verbor,"v",false,"detail log") flag.BoolVar(&help,"help",false,"help") flag.Parse() fmt.Println(host,port,verbor) }而后判断help如果为true就打印帮助信息,这里调用flag.Usage()。 if help{ flag.Usage() }else { fmt.Println(host,port,verbor) } 运行加上-h[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go -h Usage of /tmp/go-build717929224/b001/exe/flag: -H string -host addr (default "127.0.0.1") -P int nginx port (default 88) -help help -v detail log exit status 2而这个flag.Usage()可以改写10.2flag.Usagflag.Usage()flag.Usage()是一个无参的函数,我们进行重新赋值 flag.Usage = func(){ fmt.Println("Usage flagargs:\n -H --host 127.0.0.1\n -P --port 80\n -V") }而后在调用,就发现已经被改写了package main import ( "flag" "fmt" ) func main(){ var port int var host string var verbor bool var help bool flag.IntVar(&port,"P",88,"nginx port") flag.StringVar(&host,"H","127.0.0.1","-host addr") flag.BoolVar(&verbor,"v",false,"detail log") flag.BoolVar(&help,"help",false,"help") flag.Usage = func(){ fmt.Println("Usage flagargs:\n -H --host 127.0.0.1\n -P --port 80\n -V") } flag.Parse() if help{ flag.Usage() }else { fmt.Println(host,port,verbor) } }运行,使用-H[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go -h Usage flagargs: -H --host 127.0.0.1 -P --port 80 -V exit status 2或者我们在加一个参数,使用flag.PrintlnDefaults()10.3flag.PrintDefaultflag.PrintDefault在原来的基础上,加上flag.PrintDefaults() flag.Usage = func(){ fmt.Println("Usage flagargs: [ -H --host 127.0.0.1 -P --port 80 -V ]") flag.PrintDefaults() }代码块[root@linuxea.com /opt/Golang/work4/stdpkg]# cat flag.go package main import ( "flag" "fmt" ) func main(){ var port int var host string var verbor bool var help bool flag.IntVar(&port,"P",88,"nginx port") flag.StringVar(&host,"H","127.0.0.1","-host addr") flag.BoolVar(&verbor,"v",false,"detail log") flag.BoolVar(&help,"help",false,"help") flag.Usage = func(){ fmt.Println("Usage flagargs: [ -H --host 127.0.0.1 -P --port 80 -V ]") flag.PrintDefaults() } flag.Parse() if help{ flag.Usage() }else { fmt.Println(host,port,verbor) } }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go -h Usage flagargs: [ -H --host 127.0.0.1 -P --port 80 -V ] -H string -host addr (default "127.0.0.1") -P int nginx port (default 88) -help help -v detail log exit status 2那么,现在看到的就是自己的定义的格式。10.4flag.argsflag.args现在,假如还要传递一些没有名称的flag,就是可以使用flag.args在原有的代码上加上flag.args if help{ flag.Usage() }else { fmt.Println(host,port,verbor) fmt.Println(flag.Args()) }我们添加一个Usage的信息[args01 args02]并且在条件处理中也添加 flag.Usage = func(){ fmt.Println("Usage flagargs: [ -H --host 127.0.0.1 -P --port 80 -V ] [args01 args02]") flag.PrintDefaults() }代码块package main import ( "flag" "fmt" ) func main(){ var port int var host string var verbor bool var help bool flag.IntVar(&port,"P",88,"nginx port") flag.StringVar(&host,"H","127.0.0.1","-host addr") flag.BoolVar(&verbor,"v",false,"detail log") flag.BoolVar(&help,"help",false,"help") flag.Usage = func(){ fmt.Println("Usage flagargs: [ -H --host 127.0.0.1 -P --port 80 -V ] [args01 args02]") flag.PrintDefaults() } flag.Parse() if help{ flag.Usage() }else { fmt.Println(host,port,verbor) fmt.Println(flag.Args()) } }假如不传递任何参数,就是空的[][root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go 127.0.0.1 88 false []传入参数[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go mark linuxea.com 127.0.0.1 88 false [mark linuxea.com]并且使用-H可以看到在Usage中添加的信息。[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flag.go -H flag needs an argument: -H Usage flagargs: [ -H --host 127.0.0.1 -P --port 80 -V ] [args01 args02] -H string -host addr (default "127.0.0.1") -P int nginx port (default 88) -help help -v detail log exit status 210.5我们换一种方式,赋值给每个flag,然后使用指针调用,如下:package main import ( "flag" "fmt" ) func main(){ port := flag.Int("P",88,"nginx port") host := flag.String("H","127.0.0.1","-host addr") verbor := flag.Bool("v",false,"detail log") help := flag.Bool("help",false,"help") flag.Usage = func(){ fmt.Println("Usage flagargs: [ -H --host 127.0.0.1 -P --port 80 -V ] [args01 args02]") flag.PrintDefaults() } flag.Parse() fmt.Printf("%T %T %T %T\n",*port,*host,*verbor,*help) fmt.Printf("%v %v %v %v\n",*port,*host,*verbor,*help) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flags.go int string bool bool 88 127.0.0.1 false false-v[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flags.go -v int string bool bool 88 127.0.0.1 true false-H[root@linuxea.com /opt/Golang/work4/stdpkg]# go run flags.go -H flag needs an argument: -H Usage flagargs: [ -H --host 127.0.0.1 -P --port 80 -V ] [args01 args02] -H string -host addr (default "127.0.0.1") -P int nginx port (default 88) -help help -v detail log exit status 211.time模块导入time模块,time的类型也是time.Time。我们使用time.Now()获取当前时间示例代码package main import ( "fmt" "time" ) func main(){ now := time.Now() fmt.Printf("%T\n",now) fmt.Printf("%v",now) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time.go time.Time 2019-10-02 21:29:02.017017987 +0800 CST m=+0.000473262时间类型秒 time.Second分钟 time.Minute小时 time.Hour11.1时间转换最基础的方式是将时间转换成字符串一般来讲有这样几种方式2000/01/01 08:01:01或者2000-01-01 08:01:01在go中,2006表示年,01表示月,02表示天,小时24进制使用15,分钟使用04表示,秒使用05表示那么现在使用now.Format()来转换时间,如下func main(){ now := time.Now() fmt.Printf("%T\n",now) fmt.Printf("%v\n",now) fmt.Println(now.Format("2006-01-02 15:04:05")) fmt.Println(now.Format("2006/01/02 15:04:05")) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time.go time.Time 2019-10-02 21:48:34.622411579 +0800 CST m=+0.000180147 2019-10-02 21:48:34 2019/10/02 21:48:34年月日/时分秒假如此刻只需要年月日, now.Format("2006/01/02")即可,如果只是时分秒now.Format("15:04:05")即可package main import ( "fmt" "time" ) func main(){ now := time.Now() fmt.Println(now.Format("2006/01/02")) fmt.Println(now.Format("15:04:05")) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time.go time.Time 2019/10/02 21:50:18转换unix时间戳now.Unix()package main import ( "fmt" "time" ) func main(){ now := time.Now() fmt.Println(now.Unix()) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time.go 1570065936纳秒now.UnixNano()package main import ( "fmt" "time" ) func main(){ now := time.Now() fmt.Println(now.UnixNano()) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time.go 157006642209676561911.2转换时间将字符串转换成时间time.Parsetime.Parse又两个返回值,一个是err,一个是转换的值转换的格式必须一样示例我们定义一个时间格式,假如现在是2015/08/06 06:00:00,如下 now := "2015/08/06 06:00:00"而后使用time.Parse进行转换,在time.Parse("2006/01/02 15:04:05“)中的第一段时间是模板,第二段的时间是转换的时间。比如现在将now变量的2015/08/06 06:00:00按照2006/01/02 15:04:05格式转换成字符串。如下:这里使用t和err进行接收返回值 t,err := time.Parse("2006/01/02 15:04:05",now)而后打印fmt.Println(err,t)运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time2.go <nil> 2015-08-06 06:00:00 +0000 UTC将unix时间戳转换时间示例: at := time.Unix(0,0) fmt.Println(at)代码块package main import ( "fmt" "time" ) func main(){ at := time.Unix(0,0) fmt.Println(at) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time2.go 1970-01-01 08:00:00 +0800 CST11.3计算时间区间需要两个time类型的时间进行计算时间区间,于是我们就定义两个时间点,分别是now和date,date的时间需要通过字符串转换 now := time.Now() date := "2019/10/02 00:00:00" t,err := time.Parse("2006/01/02 15:04:05",date)然后通过now.Sum计算当前时间和date的时间差。并且打印出类型d := now.Sub(t) fmt.Println(d) fmt.Printf("%T",d)代码块package main import ( "fmt" "time" ) func main(){ now := time.Now() date := "2019/10/02 00:00:00" t,err := time.Parse("2006/01/02 15:04:05",date) fmt.Println(t,err) d := now.Sub(t) fmt.Println(d) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time3.go 2019-10-02 00:00:00 +0000 UTC <nil> 26h23m59.68928344s time.Duration当前时间与date时间差了26h23m59.68928344s,时间区间的类型是time.Duration### 11.4休眠时间time.Sleep需要设置一个时间区间,比如,休眠三秒 fmt.Println(time.Now()) time.Sleep(time.Second * 3) fmt.Println(time.Now())代码块package main import ( "fmt" "time" ) func main(){ fmt.Println(time.Now()) time.Sleep(time.Second * 3) fmt.Println(time.Now()) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time4.go 2019-10-03 10:35:32.848757428 +0800 CST m=+0.000131262 2019-10-03 10:35:35.849273679 +0800 CST m=+3.00064752211.5添加时间区间我们给当前的时间加上几个小时后打印package main import ( "fmt" "time" ) func main(){ fmt.Println(time.Now()) now := time.Now() t := now.Add(3 * time.Hour) fmt.Println(t) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time4.go 2019-10-03 10:41:26.584561434 +0800 CST m=+0.000090932 2019-10-03 13:41:26.58466329 +0800 CST m=+10800.00019273911.6解析时间区间time.ParseDuration可以将时间格式解析,time.ParseDuration又两个返回值 d,err := time.ParseDuration("3h2m5s") fmt.Println(err,d)代码块package main import ( "fmt" "time" ) func main(){ d,err := time.ParseDuration("3h2m5s") fmt.Println(err,d) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time5.go <nil> 3h2m5s并且可以转换成小时,分钟,秒,只需使用Hours,Minutes,Seconds即可fmt.Println(d.Hours())package main import ( "fmt" "time" ) func main(){ d,err := time.ParseDuration("3h2m5s") fmt.Println(err,d) fmt.Println(d.Hours()) fmt.Println(d.Minutes()) fmt.Println(d.Seconds()) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run time5.go <nil> 3h2m5s 3.0347222222222223 182.08333333333334 1092512.md5crypto/md5的计算hash,在使用md5.sum的时候需要传入一个字节,如果传入的是字符串,需要转换下,而后计算hash结果,转换后是byte类型的数组,而后将数组转换成一个16进制示例计算mark的md5值func main(){ md := md5.Sum([]byte("mark")) fmt.Println(md) }打印[root@linuxea.com /opt/Golang/work4/stdpkg]# go run md5.go [234 130 65 12 122 153 145 129 107 94 238 235 225 149 226 10]转换16进制转换成16进制,使用fmt.Printf("%x",md)即可,但是这里是16进制的int类型,这里的%x百分号小x是小写func main(){ md := md5.Sum([]byte("mark")) fmt.Printf("%x",md) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run md5.go ea82410c7a9991816b5eeeebe195e20a转换16进制字符串如果要转换成字符串,就使用fmt.Sprintf或者hex.EncodeToString进行转换。要使用hex.EncodeToString就需要导入包import "encoding/hex"Sprintf转换字符串,这里的%X将会转换成大写 md := md5.Sum([]byte("mark")) x := fmt.Sprintf("%X",md) fmt.Println(x)hex.EncodeToString转换字符串 fmt.Println(hex.EncodeToString(md[:]))代码块package main import ( "fmt" "crypto/md5" "encoding/hex" ) func main(){ md := md5.Sum([]byte("mark")) fmt.Printf("%x\n",md) fmt.Printf("%T\n",md) x := fmt.Sprintf("%X",md) fmt.Println(hex.EncodeToString(md[:])) fmt.Println(x) fmt.Printf("%T",x) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run md5.go ea82410c7a9991816b5eeeebe195e20a [16]uint8 ea82410c7a9991816b5eeeebe195e20a EA82410C7A9991816B5EEEEBE195E20A string12.1md5.New批量计算通常值比较小直接就可以进行计算,如果值比较大,就可以使用md5.New一个对象进行批量计算,但是计算的结果和一次计算也是一样的。示例定义一个m的md5.Newm := md5.New()而后通过m.Write批量计算m.Write([]byte("m")) m.Write([]byte("a")) m.Write([]byte("r")) m.Write([]byte("k"))而后通过sum计算,但是这里sum传递一个nil即可,因为这里没有值fmt.Printf("%x\n",m.Sum(nil))代码块[root@linuxea.com /opt/Golang/work4/stdpkg]# cat md52.go package main import ( "fmt" "crypto/md5" ) func main(){ m := md5.New() m.Write([]byte("m")) m.Write([]byte("a")) m.Write([]byte("r")) m.Write([]byte("k")) fmt.Printf("%x\n",m.Sum(nil)) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run md52.go ea82410c7a9991816b5eeeebe195e20a13.base64使用base64,需要导入"encoding/base64",转换成string类型,加上EncodeToStringbase64编码和解码都较为简单编码示例package main import ( "encoding/base64" "fmt" ) func main(){ e := base64.StdEncoding.EncodeToString([]byte("mark")) fmt.Println(e) } 运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run base64.go bWFyaw==解码示例解码使用base64.StdEncoding.DecodeString,会返回两个返回值,这里使用bytes和err接收package main import ( "encoding/base64" "fmt" ) func main(){ e := base64.StdEncoding.EncodeToString([]byte("mark")) fmt.Println(e) bytes,err := base64.StdEncoding.DecodeString(e) fmt.Println(string(bytes),err) }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run base644.go bWFyaw== mark <nil>除了这些还有URLEncoding,RawURLEncoding,RawEncoding14.日志[log]log模块,首先要导入log模块log示例package main import ( "log" ) func main(){ log.Printf("[info] %s","susu") }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run log.go 2019/10/03 15:47:13 [info] susulog和Panic示例Panicf会答应日志并触发一个Panicfpackage main import ( "log" ) func main(){ log.Printf("[info] %s","susu") log.Panicf("[Panicf] %s","error") }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run log.go 2019/10/03 15:55:23 [info] susu 2019/10/03 15:55:23 [Panicf] error panic: [Panicf] error goroutine 1 [running]: log.Panicf(0x4c673f, 0xb, 0xc000043f78, 0x1, 0x1) /usr/local/go/src/log/log.go:340 +0xc0 main.main() /opt/Golang/work4/stdpkg/log.go:8 +0xcb exit status 2log.Fatalf示例Fatalf在打印日志后也会退出package main import ( "log" ) func main(){ log.Printf("[info] %s","susu") //log.Panicf("[Panicf] %s","error") log.Fatalf("[Fatalf] %s","Fatalf") }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run log.go 2019/10/03 16:00:27 [info] susu 2019/10/03 16:00:27 [Fatalf] Fatalf exit status 1log.SetPrefix示例,日志加前缀日志加前缀[SetPrefix-],如下:log.SetPrefix("SetPrefix-")将这段放在哪里,后面的日志中就会有这个前缀,package main import ( "log" ) func main(){ log.Printf("[info] %s","susu") log.SetPrefix("SetPrefix-") log.Fatalf("[Fatalf] %s","Fatalf") }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run log.go 2019/10/03 16:34:05 [info] susu SetPrefix-2019/10/03 16:34:05 [Fatalf] Fatalf exit status 1日志加上文件名log.SetFlags(log.Flags() | log.Lshortfile ),Lshortfile打印的是文件名ipackage main import ( "log" ) func main(){ log.Printf("[info] %s","susu") log.SetPrefix("SetPrefix-") log.SetFlags(log.Flags() | log.Lshortfile ) log.Fatalf("[Fatalf] %s","Fatalf") }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run log.go 2019/10/03 17:13:19 [info] susu SetPrefix-2019/10/03 17:13:19 log.go:14: [Fatalf] Fatalf exit status 1log.SetFlags(log.Flags() | log.Llongfile),Llongfile打印的是文件全路径package main import ( "log" ) func main(){ log.Printf("[info] %s","susu") log.SetPrefix("SetPrefix-") log.SetFlags(log.Flags() | log.Llongfile) log.Fatalf("[Fatalf] %s","Fatalf") }运行[root@linuxea.com /opt/Golang/work4/stdpkg]# go run log.go 2019/10/03 17:14:19 [info] susu SetPrefix-2019/10/03 17:14:19 /opt/Golang/work4/stdpkg/log.go:14: [Fatalf] Fatalf exit status 1
2020年12月11日
4,316 阅读
0 评论
0 点赞
2020-12-10
linuxea:go基准测试和单元测试(36)
一般而言,我们通过包中的函数调用来做一些测试,比如正常的调用代码,如果错误然后追寻代码位置和行数来判断,如下:7.单元测试示例假设现在创建一个目录codetest,而后放一段代码,如,add函数,做一个加法运算,如下[root@linuxea.com /opt/Golang/inTest]# cat codetest/calc.go package codetest func Add(a,b int) int { return a + b }而后在main函数中调用[root@linuxea.com /opt/Golang/inTest]# cat main.go package main import ( "testmod/info" "testmod/codetest" "fmt" ) func main(){ fmt.Println(info.Name) a := codetest.Add(1,2) fmt.Println(a) }运行[root@linuxea.com /opt/Golang/inTest]# go run main.go mark 3但是这种方式并不可靠。我们可以使用go的单元测试。当我们对代码进行重新修改后,我们有必要对一些模块进行单元测试以确保代码运行正常。我们做一个简单的示例。测试上面Add的函数7.1单元测试还是如上所示,我们仍然测试ADD函数,加入go的测试风格。测试函数需要导入testing包,我们在calc的目录下创建一个go文件,文件中函数名称都是以Test开头,传入一个参数t,是*testing.T指针类型,在测试函数中调用函数进行返回值测试,当测试失败可通过testing.T结构体的Error*函数抛出错误func TestAdd(t *testing.T){}而后直接调用Add函数,如下:func TestAdd(t *testing.T){ if 4 != Add(1,2){ t.Errorf("1加2不等于3") } }如上所示,调用Add(1,2)的结果如果不等于4,就抛出错误代码块[root@linuxea.com /opt/Golang/inTest/codetest]# cat calc_test.go package codetest import "testing" func TestAdd(t *testing.T){ if 4 != Add(1,2){ t.Errorf("1加2不等于3") } }而后我们运行go test testmod/codetestgo test testmod/codetest中的testmod是modules中init时候的名字,codetest是当前目录下的包名[root@linuxea.com /opt/Golang/inTest/codetest]# go test testmod/codetest --- FAIL: TestAdd (0.00s) calc_test.go:7: 1加2不等于3 FAIL FAIL testmod/codetest 0.003s我们修改成正确的看看。把条件判断改成3。很明显,1+2,是等于3的package codetest import "testing" func TestAdd(t *testing.T){ if 3 != Add(1,2){ t.Errorf("1加2不等于3") } }运行[root@linuxea.com /opt/Golang/inTest/codetest]# go test testmod/codetest ok testmod/codetest (cached)7.2测试覆盖率-coverprofile我们在添加一个函数在calc.go中# cat calc.go package codetest func Add(x,y int) int { if x > 0{ return x + y }else { return x } } func Multi(x,y int) int { return x * y }测试文件calc_test.gopackage codetest import "testing" func TestAdd(t *testing.T){ if 3 != Add(1,2){ t.Errorf("1加2不等于3") } }运行[root@linuxea.com /opt/Golang/inTest/codetest]# go test testmod/codetest -coverprofile=calc.out ok testmod/codetest 0.002s coverage: 50.0% of statements这时候会产生一个calc.out文件列表:[root@linuxea.com /opt/Golang/inTest/codetest]# ll total 12 -rw-r--r-- 1 root root 137 Oct 2 10:04 calc.go -rw-r--r-- 1 root root 164 Oct 2 10:04 calc.out -rw-r--r-- 1 root root 119 Oct 2 10:04 calc_test.go7.3查看cover文件使用go tool cover -html calc.out[root@linuxea.com /opt/Golang/inTest/codetest]# go tool cover -html calc.out HTML output written to /tmp/cover001206950/coverage.html这时候生成了一个html的文件存放在/tmp/cover001206950/coverage.html红色是未覆盖的测试7.4多条件测试覆盖率上述中,只覆盖率判断了x大于0的代码,在覆盖测试else这块,如下:func TestAdd2(t *testing.T){ if -1 != Add(-1,3){ t.Errorf("-1") } }代码块package codetest import "testing" func TestAdd(t *testing.T){ if 3 != Add(1,2){ t.Errorf("1加2不等于3") } } func TestAdd2(t *testing.T){ if -1 != Add(-1,3){ t.Errorf("-1") } }运行[root@linuxea.com /opt/Golang/inTest/codetest]# go test testmod/codetest -coverprofile=calc.out ok testmod/codetest 0.002s coverage: 75.0% of statements转换html文件[root@linuxea.com /opt/Golang/inTest/codetest]# go tool cover -html calc.out HTML output written to /tmp/cover693930635/coverage.html如下:两个if分支都被测试到,所以变成了绿色。8.基准测试基准测试通常用来测试性能,函数使用Beanchmark开头,参数也是*testing.B示例创建一个函数名称为Fact的阶层函数func Fact(n int) int { if n == 0 { return 1 } return n * Fact(n-1) }代码块package codetest func Add(x,y int) int { if x > 0{ return x + y }else { return x } } func Multi(x,y int) int { return x * y } func Fact(n int) int { if n == 0 { return 1 } return n * Fact(n-1) }在calc_test.go中基准测试写法如下:func BeanchmarkFact(b *testing.B) { for i :=0;i <=20000;i++{ Fact(i) } }代码块package codetest import "testing" func TestAdd(t *testing.T){ if 3 != Add(1,2){ t.Errorf("1加2不等于3") } } func TestAdd2(t *testing.T){ if -1 != Add(-1,3){ t.Errorf("-1") } } func BeanchmarkFact(b *testing.B) { for i :=0;i <=20000 ;i++{ Fact(i) } }bench在执行go test的时候 要加-bench参数[root@linuxea.com /opt/Golang/inTest/codetest]# go test testmod/codetest -bench . goos: linux goarch: amd64 pkg: testmod/codetest BenchmarkFact-2 1 1376384478 ns/op PASS ok testmod/codetest 1.381sbenchmem可以加benchmem查看内存使用[root@linuxea.com /opt/Golang/inTest/codetest]# go test testmod/codetest -bench . -benchmem goos: linux goarch: amd64 pkg: testmod/codetest BenchmarkFact-2 1 1399430216 ns/op 0 B/op 0 allocs/op PASS ok testmod/codetest 1.403s
2020年12月10日
2,446 阅读
0 评论
0 点赞
1
2
...
8