Go struct结构体
本文最后更新于:10 天前
Golang中没有类的概念,Golang中的结构体和其他语言中的类有点类似,和他语言的面向对象相比,Golang语言的结构体具有更高灵活性和扩展性
Golang中基础数据类型表示一些事物的基本属性,但是当我们想表达一个事物的全部或者部分的属性时候,这时候在用单一的数据类型就无法满足需求了,Golang提供了一种自定义数据类型,可以封装多个基本数据类型, 这种数据类型叫做结构体,英文名称 strcut
, 也就是我们可以通过struct
来定义自己的类型了
1 结构体是值类型
结构体首字母可以大写也可以小写,大写表示这个结构体(包括结构体里面的字段名称也是一样的)是共有的,其他包可以调用,小写是不可以,只可以内部函数自己使用
2 Golang中 type关键词
Golang中通过type关键词定义一个结构体,type可以自定义类型和类型别名
2.1 自定义类型
在go语言中有一些基本的数据类型,如string 整形,浮点型,布尔等类型,Go语言中可以使用type关键字来定义自定义类型。
type myInt int
上面代码表示: 将myInt 定义为int类型,通过type关键词字的定义。myInt就是一种新的类型,它具有int的特性
2.2 类型别名
类型别名规定: TypeAlias 只是Type的别名,本质上TypeAlias与Type是同一个类型
package main
import "fmt"
func main() {
type myInt int //自定义int类型
type myFn func(int, int) int //自定义方法类型
type myFloat = float64 //类型别名 : 从打印结果可以看到,类型别名打印的还是底层的类型
var a myInt = 10
var b myFloat = 10.1
fmt.Printf("a类型: %T\n", a) //打印结果 a类型: main.myInt
fmt.Printf("b类型: %T\n", b) //打印结果:b类型: float64
}
3 结构体定义和初始化
3.1 结构体的定义
type 累姓名 struct {
字段 字段类型
字段 字段类型
...
}
3.2 结构体实例化
初始化结构体的七种方法
package main
import (
"fmt"
)
type Person struct {
name string
age int
sex string
}
func main() {
var p1 Person
p1.name = "bds"
p1.sex = "nan"
p1.age = 20
fmt.Printf("p1: %v 类型: %T\n", p1, p1) //value: {bds 20 nan} 类型: main.Person
fmt.Printf("p1: %#v 类型: %T\n", p1, p1) //value: main.Person{name:"bds", age:20, sex:"nan"} 类型:main.Person
var p2 = new(Person)
p2.name = "bds2"
p2.sex = "nan"
p2.age = 22
fmt.Printf("p2值:%#v,类型:%T\n", p2, p2)
var p3 = &Person{}
p3.name = "bds3"
p3.sex = "nan"
p3.age = 23
fmt.Printf("p3值:%#v,类型:%T\n", p3, p3)
var p4 = Person{
name: "bds4",
sex: "nan",
age: 24,
}
fmt.Printf("p4值:%#v,类型:%T\n", p4, p4)
var p5 = &Person{
name: "bds5",
age: 25,
sex: "nan",
}
fmt.Printf("p5值:%#v,类型:%T\n", p5, p5)
var p6 = &Person{
name: "bds6",
}
fmt.Printf("p6值:%#v,类型:%T\n", p6, p6)
var p7 = &Person{
"bds",
21,
"男",
}
fmt.Printf("p7值:%#v,类型:%T\n", p7, p7)
}
/*
p1: {bds 20 nan} 类型: main.Person
p1: main.Person{name:"bds", age:20, sex:"nan"} 类型: main.Person
p2值:&main.Person{name:"bds2", age:22, sex:"nan"},类型:*main.Person
p3值:&main.Person{name:"bds3", age:23, sex:"nan"},类型:*main.Person
p4值:main.Person{name:"bds4", age:24, sex:"nan"},类型:main.Person
p5值:&main.Person{name:"bds5", age:25, sex:"nan"},类型:*main.Person
p6值:&main.Person{name:"bds6", age:0, sex:""},类型:*main.Person
p7值:&main.Person{name:"bds", age:21, sex:"男"},类型:*main.Person
*/
4 结构体方法和继承者
在Go语言中,没有类的概念,但是可以给结构体定义方法,就是定义了一个接受者函数,接收者的概念就类似于其他语言中的this 或者self
方法如下:
func (接收者变量 接受者类型) 方法名字(参数列表) (返回参数) {
函数体
}
接受者变量: 接受者中的参数变量名字在命名时候,官方建议使用接收者类型名字的第一个小写字母,而不是self,this之类的名字,例如Person类型的接收者变量名字应该为p
接受者类型: 接收者类型和参数类似,可以是指针类型和非指针类型
方法名,参数列表,返回参数 具体格式与函数定义相同
例子: 给结构体Persion 定义一个打印Pricntinfo方法和SetInfo方法
package main
import "fmt"
type Person struct {
Name string
Age int
worker string
}
func (p Person) Pringinfo() {
fmt.Printf("姓名:%v,年龄:%v\n", p.Name, p.Age)
}
// 因为传入的是指针变量,所以这里修改值,会直接影响原来的结构体里面的值。
func (p *Person) SetInfo() {
p.Name = "fanbu"
p.Age = 1
p.worker = "golang"
}
func main() {
var p1 = Person{
Name: "bds1",
Age: 21,
worker: "linux",
}
p1.Pringinfo()
p1.SetInfo()
p1.Pringinfo()
}
/*
姓名:bds1,年龄:21
姓名:fanbu,年龄:1
*/
5 给自定义类型添加方法
package main
import "fmt"
type myInt int //比如我们也可以给myInt 定义方法
func (m myInt) Print() {
fmt.Println("我是myInt 自定义方法")
}
func main() {
var a myInt = 10
a.Print()
}
6 结构体的匿名字段和其他类型使用
结构体允许其成员没有字段名字而只有类型。这种没有名字的字段就成为匿名字段,匿名字段名字必须有唯一性,所以如果一个结构体里面有同样类型的时,就会报错。
6.1 使用其他数据类型
package main
import "fmt"
/*
结构体字段类型可以是 基本数据类型 ,也可以是 切片, Map 以及 结构体
如果结构体的字段类型是: 指针 slice ,map的零值都是nil 即还没有分配内存空间
如果需要使用这样的字段: 需要先make ,才能使用
*/
type Person1 struct {
Name string
hobby []string
map1 map[string]string
}
func main() {
var p1 Person1
p1.Name = "bds"
p1.hobby = make([]string, 4, 4)
p1.hobby[0] = "sleep"
p1.hobby[1] = "moving"
p1.map1 = make(map[string]string)
p1.map1["phone"] = "1333123123"
p1.map1["addr"] = "BeiJing"
fmt.Printf("%#v", p1)
}
//main.Person1{Name:"bds", hobby:[]string{"sleep", "moving", "", ""}, map1:map[string]string{"addr":"BeiJing", "phone":"1333123123"}}
6.2 结构体嵌套
有名字的嵌套
type Person1 struct {
Name string
hobby []string
map1 map[string]string
Body BodyInfo
}
type BodyInfo struct {
weight string
age int
}
func main() {
var p2 Person1
p2.Name = "bds1"
p2.Body.weight = "180" //嵌套的结构体赋值通过 点. 操作
p2.Body.age = 18
fmt.Printf("%v", p2)
fmt.
}
匿名嵌套
type Person1 struct {
Name string
hobby []string
map1 map[string]string
BodyInfo //匿名字段 Persion1结构体嵌套BodyInfo结构体
}
type BodyInfo struct {
weight string
age int
}
func main() {
var p2 Person1
p2.Name = "bds1"
p2.BodyInfo.weight = "180"
p2.BodyInfo.age = 18
fmt.Printf("%v\n", p2)
fmt.Println(p2.BodyInfo.age) //18
// 如果是匿名字段嵌套,可以直接使用匿名字段里面的字段进行取值。
fmt.Println(p2.age) //18 也就是 先在当前结构体查找,找不到去结构体里面查找。然后取值。
}
7 结构体的继承
package main
import "fmt"
//父亲结构体
type Animal struct {
Name string
}
//儿子结构体 ,继承了父亲的结构体里面的属性和方法
type Dog struct {
color string
age int
wang string
Animal //其实就是通过嵌套来实现继承
}
func (a Animal) do() {
fmt.Printf("%v\n", a.Name)
}
// 继承父亲的 Name属性
func (d Dog) run() {
fmt.Printf("%v 在%v\n", d.Name, d.wang)
}
func main() {
var s1 = Dog{
wang: "旺旺旺",
color: "writer",
Animal: Animal{
Name: "小花",
},
}
fmt.Println(s1)
//因为Dog 继承父亲。所以可以用父亲的do方法
s1.do()
s1.run()
}
/*
{writer 0 旺旺旺 {小花}}
小花 在运动园
小花 旺旺旺
*/
8 结构体 json数据转换
比如我们Golang要给app或者小程序提供api接口数据,这个时候就需要涉及到结构体和json之间的相互转换
Golang Json序列化是指: 把结构体数据转化为json格式的字符串,Golang json的反序列化是指把json数据转为Golang中的结构体对象
Golang中的序列化和反序列化主要通过encoding/json包中的json.Marshal()和json.Unmarshal()
package main
import (
"encoding/json"
"fmt"
)
type Stu struct {
Name string
Age int
class string
}
func main() {
var s = Stu{
Name: "bds1",
class: "高中",
Age: 18,
}
fmt.Println(s)
stuByte, err := json.Marshal(s)
if err != nil {
fmt.Println(err)
} else {
jsonStu := string(stuByte)
fmt.Println(jsonStu) //转换成字符串
}
}
Json 转换为 结构体
var b = `{"Name":"bds2","Age":19}`
var stuJson = Stu{}
err1 := json.Unmarshal([]byte(b), &stuJson)
if err1 != nil {
fmt.Println(err1)
} else {
fmt.Println(stuJson)
fmt.Println(stuJson.Name)
}
9 结构体标签Tag
Tag
是结构体的元信息
,可以在运行的时候通过反射
的机制读取出来,Tag在结构体字段的后方定义,是一对反引号
包裹起来的,具体格式如下:
`key:"value" key2:"value2"`
结构体tag是由一个或者多个键值对组成,键与值使用冒号分隔,值用双引号阔起来,同一个结构体字段可以设置多个键值对tag,不同的键值对之间使用空格分割
注意: 不在key和value之间加上空格
package main
import (
"encoding/json"
"fmt"
)
type stuf struct {
Name string `json:"name"` //通过tag 来自定义转换成json格式后的key
Age int `json:"age"`
}
func main() {
var student = stuf{
Name: "bds1",
Age: 19,
}
jsonStudent, err := json.Marshal(student)
if err != nil {
fmt.Println(err)
} else {
//通过定义tag标签 我们可以看到最后的json格式的key是 我们结构体中自定义的tag标签里面的key。
fmt.Println(string(jsonStudent)) //{"name":"bds1","age":19}
}
}
举一个稍微复杂的例子
package main
import (
"encoding/json"
"fmt"
)
type class struct {
Name string `json:"name"`
Students []student `json:"stu"` //切片结构体类型
}
type student struct {
Name string `json:"name"`
Age int `json:"age"`
Addr string `json:"address"`
}
func main() {
var c1 = class{
Name: "一年一班",
Students: make([]student, 0),
}
for i := 0; i < 10; i++ {
var stu = student{
Name: fmt.Sprintf("stu_%v", i),
Age: 18,
Addr: fmt.Sprint("Bj_1001", i),
}
c1.Students = append(c1.Students, stu)
}
fmt.Println(c1)
JsonClass, err := json.Marshal(c1)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(JsonClass))
}
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!