重学Go语言 | Go Struct详解
我正在参加「掘金·启航计划」
在其他编程语言中(如Java
),我们可以使用类(Class
)来描述比较复杂的实体,比如定义用户信息(名称,年龄等)或者一个订单信息(订单号,下单时间等):
public class User{
public String name;
public int age;
public String email;
}
而Go
语言并没有类(Class
)的概念,如果想在Go
语言表示用户、订单等复杂的实体,结构体(struct
)是一个不错的选择。
什么是结构体
结构体
,英文叫struct
,是一种由一个或者多个成员组成的复合数据类型,通过结构体,我们可以在程序中定义复杂的数据实体,比如用户或订单信息等:
type Order struct{
ID string
CreatedAt int
}
结构体的使用
在使用Go
内置的数据类型(如int
,float
,slice
等)时,我们一般使用该数据类型直接定义变量,比如:
var i int
var s string
之所以可以这样用,是因为这些基础数据类型是Go内置的数据类型。
但要使用结构体,则必须自己先创建一个结构体,也就是说,我们要自己创建一个结构体数据类型,这个结构体的成员的名称与类型由我们自己定义,然后再使用该结构体声明变量。
创建结构体
Go语言的结构体创建语法格式如下:
type StructName struct{
FieldName FieldType
FieldName FieldType
...
FieldName FieldType
}
上面语法各个部分表示:
StructName
表示结构体的名称,比如User
,首字母大写表示可以在其他包中使用该结构创建变量。FieldName
表示成员名,如Name
,首字母大写表示,可以在其他包中调用该成员。FieldType
表示成员的数据类型,比如int
。
上面我们已经讲解了创建结构体的语法格式,接下来,我们来创建一个结构体来表示用户信息:
type User struct{
ID string
Name string
Age int
Email string
}
相同数据类型的成员也可以写在同一行:
type User struct{
ID,Name,Email string
Age int
}
使用结构体声明变量
创建好结构体之后,就可以使用该结构体来声明变量了:
var u User
直接使用结构体定义变量,如果没有给各个成员赋初始化,则各成员为其数据类型的默认值。
通过结构体的字面量,可以在声明时给结构体的各个成员赋初始值:
var u1 User = User{
ID:"001",
Name:"test1",
Age:20,
Email:"test1@163.com",
}
u2 := User{
ID:"002",
Name:"test2",
Age:23,
Email:"test2@163.com",
}
也可以按结构体成员的顺序给结构体赋初值:
//正确
var u1 User = User{"001","test",20,"test@163.com"}
//不按成员顺序,错误
var u2 User = User{"001","test","test@163.com",20}
访问结构体的成员
声明了结构体变量后,可以使用点号(.
)来访问结构体的成员或给成员赋值:
u1.Name = "test11"
fmt.Println(u1.Name)
也可以对结构体的成员进行取址操作:
name := &u1.Name
&name = "ttt"
//u1的Name成员已经被修改
fmt.Println(u1.Name)
将结构体作为函数的参数
结构体不是引用类型,因此当将结构体变量作为实参传给函数时,会复制给形参,因此如果在函数内修改结构体,并不会生效
u := User{"001","test",20,"test@163.com"}
func ChangeName(u User){
u.Name = "1111"
}
fmt.Println(u)
如果想要在函数内修改结构体,可以传入结构体指针:
func ChangeName(u *User){
u.Name = "2222"
}
fmt.Println(&u)
结构体的比较
同一个结构体声明的变量可以进行比较,如果每个成员的值相等,则两个结构体变量相等,否则为不相等:
u1 := User{"001","test",20,"test@163.com"}
u2 := User{"001","test",20,"test@163.com"}
u3 := User{"002","test",20,"test@163.com"}
if u1 == u2 {
fmt.Println("相等")
}else{
fmt.Println("不相等")
}
if u1 == u3 {
fmt.Println("相等")
}else{
fmt.Println("不相等")
}
结构体的嵌套
结构体的嵌套有两种方式,一种是像其他数据类型一样,在一个结构体中,使用另一个结构体定义成员:
type Address struct {
ID int
City string
Province string
}
type Customer struct {
ID int
Name string
Addr Address //另一个结构体
}
c := Customer{ID: 1, Name: "test", Addr: Address{1, "广东", "广州"}}
fmt.Println(c.Addr.ID)
fmt.Println(c.Addr.City)
如上代码所示,Customer
结构体要访问Address
结构体的成员,必须通过成员名,访问路径变长。
另外一个是使用匿名嵌入的方式:
type Customer struct {
ID int
Name string
Address
}
c := Customer{ID: 1, Name: "test", Address: Address{1, "广东", "广州"}}
fmt.Println(c.City)
匿名嵌入的方式,可以让最外层的结构体像访问自己的成员一样,访问嵌入结构体的成员,不过如果有同名成员,比如上面两个结构体都有成员ID
,这时候要获取匿名结构体的ID
,仍然只能通过嵌入结构体来访问:
fmt.Println(c.Address.ID)
结构体不能包含自己,但可以包含一个指向自己类型的指针:
//错误
type Node struct{
ID
Name
Node
}
//错误
type Node struct{
ID
Name
n Node
}
//正确
type Node struct{
ID
Name
*Node
}
//正确
type Node struct{
ID
Name
n *Node
}
小结
结构体是一种很灵活的结构体,通过其中的成员,可以描述不同的实体,所以在开发中会经常使用。
在这篇文章中,我们主要讲了以下几点:
- 什么是结构体
- 如何创建结构体、使用结构体声明变量
- 结构体的比较
- 内嵌结构体
转载自:https://juejin.cn/post/7247321275684618301