您的位置 首页 golang

Golang之Struct

写在前面:

0x01 — Struct使用

Struct结构体的关键字是struct,定义时可以使用type进行定义:

 type person struct {
   sex int
   age int
   name string
}  

定义一个struct方式和其他语言的class类似, 定义成员变量时记得不要加逗号 ,成员名称后面需要根成员类型。

使用时需要先声明后初始化

 package main

import (
   "testing"
)

// 个人结构
type person struct {
   sex int
   age int
   name string
}
type Addr struct {
   name string
   city string
   addr string
}

// 以家庭为示例,包含家庭创建时间,家庭成员,父亲,母亲,孩子
type Family struct {
   Addr             // 此处为类似继承功能,Family将会拥有Addr下的所有成员属性,
   //Addr Addr // 这种写法是标准写法,如果引用名称和类型一致,则可以省略类型
   marryTime int
   father person
   mather *person
   children []*person
}

//结构体使用
func TestStruct(t *testing.T) {
   var tf1 Family
   tf1.marryTime = 10
   tf1.addr = "银河系 太阳系 地球市 中国01号" // 在定义Family时没有定义addr,但是我们可以额外定义,定义后在Family生命周期生效。
   tf1.Addr = Addr{"银河","太阳","地球1号"}
   tf1.mather = &person{1,30, "mama"}
   tf1.father = person{sex: 2, age: 32, name:"papa"}
   tf1.children = []*person{
      {2,2, "tom"}, // 因为明确要获取结构体指针的数组,所以可以省略名称
      &person{2,5, "davy"},
   }
   t.Log("打印Tf1:", tf1) // 可以打印出tf1的机构
   t.Log("tf1 家庭的地址:", tf1.addr)
   t.Log("tf1 家庭的地址Addr.name:", tf1.Addr.name)
   t.Log("tf1 家庭的地址Addr.city:", tf1.Addr.city)
   t.Log("tf1 家庭的地址Addr.addr:", tf1.Addr.addr)
   t.Logf("tf1 家庭建立已经 %d 年了", tf1.marryTime)
   t.Log("tf1 家庭的父亲:", tf1.father.name)
   t.Log("tf1 家庭的母亲:", tf1.mather.name)
   for _,i := range tf1.children { // 此处索引不需要则使用_来代替
      t.Log("tf1 家庭的孩子:", i.name)
   }
}  

创建方式就是如上,创建父亲和母亲的实体时,可以不需要指明成员名称,如目前,可以直接把值加进去,也可以想申请父亲实体一样指明成员的名称。

看到这里可能会有疑问,为什么父亲和母亲签名有没有星号结果都是一样的呢?关于指针的介绍,我会专门重点介绍下,目前只需要知道在结构体中,访问结构体的成员和访问结构体指针的成员方式是一样的就可以。

0x02 — Struct Tag

结构体和JSON的结构很像, JSON是一种用于发送和接收结构化信息的标准协议 对JavaScript中各种类型的值——字符串、数字、布尔值和对象——Unicode本文编码,它可以用有效可读的方式表示基础数据类型和数组、slice、结构体和map等聚合数据类型。JSON的对象类型可以用于编码Golang的map类型(key类型是字符串)和结构体。

 // struct tag
type ProductLicense struct {
   SystemID     uint     `json:"system_id"`         //系统id
   Name         string   `json:"name"`              //服务名
   Key          string   `json:"key"`               //服务key
   UsageLimit   int64    `json:"usage_limit"`       //使用次数
   IsActive    bool                         //是否生效
}
func TestPl(t *testing.T) {
   plList := []ProductLicense{
      {21, "内存服务", "BX-0101", 10000, true},
      {22, "磁盘服务", "BX-0102", 10000, true},
      {23, "认证服务", "BX-0103", 10000, true},
      {24, "工具服务", "BX-0104", 10000, false},
   }
   
   d,err := json.Marshal(plList)
   if err == nil {
      t.Logf("服务认证控制:\n%s" ,d)
   } else {
      t.Log("结构无法转换")
   }

   // 下面这段代码是推荐写法,融合了GO的特色,条件中赋值,同时进行校验,还保持了快速错误抛出的原则
   //if d, err := json.Marshal(plList); err != nil {
   // t.Log("结构无法转换")
   //} else {
   // t.Logf("服务认证控制:\n%s" ,d)
   //}
}  

输出:

 === RUN   TestPl
    struct_test.go:64: 服务认证控制:
        [{"system_id":21,"name":"内存服务","key":"BX-0101","usage_limit":10000,"IsActive":true},
        {"system_id":22,"name":"磁盘服务","key":"BX-0102","usage_limit":10000,"IsActive":true},
        {"system_id":23,"name":"认证服务","key":"BX-0103","usage_limit":10000,"IsActive":true},
        {"system_id":24,"name":"工具服务","key":"BX-0104","usage_limit":10000,"IsActive":false}]
--- PASS: TestPl (0.00s)
PASS  

上面代码中ProductLicense结构体中,成员后面通过“符号进行了tag标记,在转换成json时,使用后面的名字代替,如果没有声明tag,则使用原名称作为json中的名称(IsActive)。

大家应该发现,isDelete转换json时,输出中没有这个成员,这是因为成员变量为小写默认为私有变量,不能进行转换,只有首字母大写的成员才会被转换,这个逻辑贯穿整个Golang体系。

0x03 — type 声明

在Golang可以通过type来自定义一种类型

 type Centimeters float64    // 厘米
type Decimeter float64 // 分米

const (
    centt Centimeters = -273.15
    Deci Decimeter = 0
)  

我们可以通过type关键字声明两个类型一个Centimeters,一个是Decimeter,两个类型都是float64类型, 它们虽然有着相同的底层类型float64,但是它们是不同的数据类型,因此它们不可以被相互比较或混在一个表达式运算 ,两个类型不可隐性转换。

0x03 — 总结

Struct结构体使用中要注意类似继承的结构,虽然实现了类似继承的功能,但是不完全是继承的概念,后续在将方法时会明确。

结构体在后面学习框架比如grom等的时候,会遇到特殊的tag类型,原理都是类似,只需要多多实践。

文章来源:智云一二三科技

文章标题:Golang之Struct

文章地址:https://www.zhihuclub.com/97272.shtml

关于作者: 智云科技

热门文章

网站地图