匿名结构体,顾名思义,就是没有名称的,也是只需要使用一次的。或者是函数内的,比如配置,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("%Tn",me)
fmt.Printf("%#vn",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("%#vn",me)
如下:
package main
import "fmt"
func main(){
var me struct {
ID int
Name string
}
fmt.Printf("%Tn",me)
fmt.Printf("%#vn",me)
me.ID = 1
me.Name = "mark"
fmt.Println(me.ID,me.Name)
fmt.Printf("%#vn",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的属性上填写上面结构体的名称Address
type 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("%#vn",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("%#vn",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("%#vn",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("%#vn",me)
me02 := Employee{
User: User{
ID:1,
Name: "mark",
Addr:Address{
Region:"上海市",
Street:"徐汇区",
No:"10501",
},
},
Salary: 10023.3,
}
fmt.Printf("%#vn",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.3
5.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("%#vn",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("%#vn",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("%#vn",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,%#vn",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("%#vn",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的零值就是nil
func main(){
var mm User
fmt.Printf("%#vn",mm)
}
初始化与其他方式一样,不通的是在Address上需要使用指针方式
mm = User{
ID:1,
Name: "mark",
Addr:&Address{
Region: "上海市",
Street:"淞虹路",
No:"12362",
Name:"MarkSugar",
},
}
fmt.Printf("%#vn",)
代码块如下:
[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("%#vn",mm)
mm = User{
ID:1,
Name: "mark",
Addr:&Address{
Region: "上海市",
Street:"淞虹路",
No:"12362",
Name:"MarkSugar",
},
}
fmt.Printf("%#vn",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("%#vn",me)
me = Employee{
Salary: 1.5,
User: &User{
ID:1,
Name:"mark",
Addr:Address{
Region:"北京市",
Street:"望京",
},
},
}
fmt.Printf("%#vn",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("%#vn",me)
me = Employee{
Salary: 1.5,
User: &User{
ID:1,
Name:"mark",
Addr:Address{
Region:"北京市",
Street:"望京",
},
},
}
fmt.Printf("%#vn",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("%#vn",me)
fmt.Printf("%#vn",me2)
change(me2)
fmt.Printf("%#vn",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("%#vn",me)
fmt.Printf("%#vn",me2)
change(me2)
fmt.Printf("%#vn",me2)
changepoint(&me2)
fmt.Printf("%#vn",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("%#vn",me.Addr)
fmt.Printf("%#vn",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("%#vn",me.Addr)
fmt.Printf("%#vn",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("%#vn",me)
}
运行
[root@linuxea.com /opt/Golang/work5]# go run z1.go
main.User{ID:1, Name:"mark", Addr:(*main.Address)(0xc000062150)}
7.结构体可见性
结构体首先字母大写则包外可见,否则仅包内可访问。结构体属性名首字母大写包外可见,否则仅包内可访问。
总结:结构体和属性名首字母大写才能包外访问。否则就不能够在包外访问。