Go语言中的Struct

一、Go语言中没有像C#、Java一样的Class,只有Struct这样的结构体。Go语言使用type关键字来定义一个类型。

如下:

type User struct {
   Name string
   Age int32
   Sex int16
   AvatarUrl string
}

二、Struct的声明以及初始化

初始化方法一:直接定义,通过变量名.成员名的方式赋值

//初始化方法1
var user1 User
user1.Name = "BigOrange"
user1.Age = 20
user1.Sex = 1
user1.AvatarUrl = "xxxxxxx"

fmt.Println("User1:",user1)

初始化方法二:直接通过{}进行初始化,这点和C#不一样,C#初始化的时候一般用new,例如 var user  = new User{xxxxx,xxxxx,xxxx}

//初始化方法2
var user2 User = User{
   Name:"BigBanana",
   Age:23,
   Sex:0,
   AvatarUrl:"yyyyyyyyyyy",
}

fmt.Println("User2:",user2)

//初始化方法2简化
 user3 := User{
   Name:"BigBanana",
   Age:23,
   Sex:0,
   AvatarUrl:"yyyyyyyyyyy",
}

fmt.Println("User3:",user3)

  

三、Struct的指针

Struct的指针比较简单,就是通过&获取地址,此外还可以用new来返回一个对象的指针

var user4 *User = &User{
    Name:"BigPeach",
    Age:22,
    Sex:1,
    AvatarUrl:"zzzzzzz",
 }

fmt.Println("User4:",user4)
fmt.Println("User4:",*user4)

 

user5 := new(User)
user5.Name="BigGrape"
user5.Age= 25
user5.Sex= 1
user5.AvatarUrl= "mmmmmmmmm"
fmt.Println("User5:",user5)
fmt.Println("User5:",*user5)

上面第二种方式可能会有些疑问,user5不是一个指针类型吗?怎么和上面的值类型一样直接用【变量名.成员】 的方式进行赋值了呢? 不是应该 (*user5).Name 这样吗?没有错!

这是GO语言实现的一个语法糖,实际上GO语言会帮我转换。

 

四、Struct成员的内存布局以及实现构造函数

例如下面这样的一段代码

package main

import "fmt"

type AddressDemo struct {
   addr1 int32
   addr2 int32
   addr3 int32
}

func main(){
   addr := new(AddressDemo)
   fmt.Println("add1地址:",&addr.addr1)
   fmt.Println("add2地址:",&addr.addr2)
   fmt.Println("add3地址:",&addr.addr3)
}

结果:

add1地址: 0xc042060080
add2地址: 0xc042060084
add3地址: 0xc042060088

可以看出来,addr1、addr2、addr3都是int32,都是占用了4个字节,他们的地址分配都是连续的

For example: 下面这个User包,就实现了一个NewUser的方法,他就是构造函数

package User

type User struct {
   Name string
   Age int32
   Sex int16
   AvatarUrl string
}

func NewUser(name string , age int32,sex int16,avatarUrl string) *User{
   user:=new(User)
   user.Name = name
   user.Age = age
   user.Sex = sex
   user.AvatarUrl = avatarUrl

   return user
}

五、Struct中的匿名字段和嵌套

可以像下面这样声明:后两个字段没有名字

type Class struct {
   Name string
   int
   string
}

使用的时候,对于匿名的字段,直接赋值就可以了

class1:=Class{
   Name:"Class1",
   int:123,
   string:"sssssss",
}

fmt.Println("class1:",class1)

结构体的嵌套

type User struct {
   Name string
   Age int32
   Sex int16
   AvatarUrl string
}

type Class struct {
   Name string
}

type Student struct {
   User User
   Class Class
}

使用:

func main() {
   stu:=new(User.Student)
   
   stu.Class = User.Class{
      Name:"5-2",
   }
   
   stu.User = User.User {
       Name:"BigBanana",
      Sex:1,
      Age:12,
      AvatarUrl:"asdasdasd",
   }
   
   fmt.Println(stu)
}

如果是匿名结构体嵌套呢?修改一下Student

type Student struct {
   User User
   Class
}

使用在对Class这个成员进行赋值的时候,可以发现,既可以使用

   stu.Class = User.Class{
      Name:"5-2",
   }

也可以使用Name直接赋值,顺序就是现在当前的结构体找,找不到再从匿名结构体中查找,正好找到Class里面有Name

stu.Name = "5-2"

如果Class和User都是匿名结构嵌套,但是他们里面都有Name,当我们使用stu.Name的时候,那他访问的是Class里的Name还是User里面的Name? 那么岂不是冲突了? 如何处理冲突?

当我试图给stu.Name赋值的时候,编译器报错了,内容如下,也就是它找不到应该给谁赋值。

这时候要解决这个冲突,必须指定是哪个匿名字段里面的Name

stu:=new(User.Student)

stu.User.Name = "123123"
stu.Class.Name = "5-2"

stu.User = User.User {
   Name:"BigBanana",
   Sex:1,
   Age:12,
   AvatarUrl:"asdasdasd",
}

 

六、结构体内字段的可见性

和包一样,小写的字段外部不可见,大写的外部可见

 

七、结构体的Tag

tag是结构体的元信息,可以在运行的时候通过反射的机制读出来。

怎么写tag?

以`作为开头和结尾,中间是key-value形式的字符串,每一个键值对以,作为分隔。例如

type User struct {
   UserName string   `json:"userName",db:"User_Name"`
   Age int32         `json:"age"`
   Sex int16         `json:"sex"`
   AvatarUrl string  `json:"avatarUrl",db:"Avatar_Url"`
}

使用并运行:

func main() {

   user := User.User {
      UserName:"BigBanana",
      Sex:1,
      Age:12,
      AvatarUrl:"asdasdasd",
   }

   fmt.Println(user)

   data,_:=json.Marshal(user)

   fmt.Println(string(data))
   
}

结果:

{"userName":"BigBanana","age":12,"sex":1,"avatarUrl":"asdasdasd"}

可以看到,如果打了这个tag,会显示tag后面的标记名称。

此外:如果字段名称是小写,那么json输出的时候就不会有这个字段被打印了。

 

原文地址:https://www.cnblogs.com/dcz2015/p/10770917.html