golang基础小记(14)

您所在的位置:网站首页 结构体怎么定义 golang基础小记(14)

golang基础小记(14)

2024-07-09 23:17| 来源: 网络整理| 查看: 265

结构体定义

Go语言没有类的概念,但是可以通过结构体实现面向对象编程。 结构体是一种自定义数据类型,其可以封装任何类型。 示例:

type house struct { size, price float64 style string }

上例house是自定义结构体类型,包括size、price、style三个字段,可以用来描述房子的面积、价格和风格。house类型的变量可以很方便的存储房子信息。

结构体实例化

结构体是值类型,需要声明后才能使用,声明后内部成员的值默认是对应成员类型的零值。

基本实例化

使用上面定义的house举例:

var h1 house h1.size = 130 h1.style = "中国风" fmt.Printf("%v\n", h1) // {130 0 中国风} fmt.Printf("%#v", h1) // main.house{size:130, price:0, style:"中国风"} fmt.Println(h1.size) // 130

通过.来访问结构体的字段(成员变量)

匿名结构体

匿名结构体可以用来定义临时结构体。 示例:

var family struct { Mom string Dad string } family.Mom = "Mommy" family.Dad = "Daddy" fmt.Printf("%v\n", family) // {Mommy Daddy} fmt.Printf("%#v\n", family) // struct { Mom string; Dad string }{Mom:"Mommy", Dad:"Daddy"}

上例中family是struct { Mom string; Dad string }类型的变量,因为没有用type关键字定义名字,每次使用都得写清楚结构体类型。

结构体指针 使用new关键字 p1 := new(house) p1.style = "欧式" fmt.Printf("%#v\n", p1) // &main.house{size:0, price:0, style:"欧式"}

Go语言中支持对结构体指针直接使用.来访问结构体的成员。在访问的时候编译器会自动把 p1.style 转为 (*p1).style。

使用取地址符& p2 := &house{} fmt.Printf("%T\n", p2) // *main.house fmt.Printf("%#v\n", p2) // &main.house{size:0, price:0, style:""} 结构体初始化 直接声明

成员默认初始化为对应类型的零值。比如之前例子中的var h1 house。

利用键值对初始化

(1)对结构体进行键值对初始化

h3 := house{ size: 110, price: 700, } fmt.Printf("%#v\n", h3) // main.house{size:110, price:700, style:""}

没必要对每一个成员都设置初始值,未设置初始值的默认为对应类型的零值。 (2)对结构体指针进行键值对初始化

p3 := &house{ size: 110, price: 700, } fmt.Printf("%#v\n", p3) // &main.house{size:110, price:700, style:""}

(3)值的列表初始化 也就是初始化的时候省略键,只写值:

h4 := house{ 110, 940, "中国风", } fmt.Printf("%#v\n", h4) // main.house{size:110, price:940, style:"中国风"}

需要注意:省略键后,所有成员的值都需要初始化,且顺序要和结构体定义顺序相同。

构造函数

Go语言没有结构体的构造函数,但可以手动实现。实现构造函数后可以十分方便的构造结构体变量。 示例:

type house struct { size, price float64 style string } // 返回结构体指针 func newHouse(size, price float64, style string) *house { return &house{ size: size, price: price, style: style, } } func main() { p1 := newHouse(100, 80, "中国风") fmt.Printf("%#v\n", p1) // &main.house{size:100, price:80, style:"中国风"} }

上例中的newHouse函数就是一个构造函数,可以用来构造house类型的结构体。构造函数可以返回结构体,也可以返回结构体指针。当结构体比较大的时候,返回结构体会有较大的值拷贝性能开销,这时返回结构体指针更合适。

匿名字段

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为匿名字段。匿名字段默认会采用类型名作为字段名,而结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个。 示例:

type house struct { int string } func main() { h1 := house{ 100, "中国风", } fmt.Printf("%#v\n", h1) // main.house{int:100, string:"中国风"} fmt.Println(h1.string, h1.int) // 中国风 100 }

匿名字段也可以与非匿名字段混用,示例如下:

type person struct { height int int name string string } func main() { p1 := person{ height: 178, int: 100, name: "夏静怡", string: "篮球", } fmt.Printf("%#v\n", p1) // main.person{height:178, int:100, name:"夏静怡", string:"篮球"} fmt.Println(p1.height, p1.int, p1.string) // 178 100 篮球 } 嵌套结构体

嵌套结构体就是一个结构体中包含另一个结构体或结构体指针。 示例:

type address struct { province, city string } type house struct { size int addr address } func main() { h1 := house{ size: 100, addr: address{ "浙江", "杭州", }, } fmt.Printf("%#v\n", h1) // main.house{size:100, addr:main.address{province:"浙江", city:"杭州"}} // 嵌套结构体的成员可以通过'.'一层一层的访问 fmt.Println(h1.addr.city) // 杭州 }

当嵌套结构体采用匿名字段的方式,其成员可以直接访问。 示例:

type address struct { province, city string } type house struct { size int address // 匿名嵌套结构体 } func main() { h1 := house{ size: 100, address: address{ "浙江", "杭州", }, } fmt.Printf("%#v\n", h1) // main.house{size:100, address:main.address{province:"浙江", city:"杭州"}} // 匿名字段可以省略 fmt.Println(h1.address.city, h1.city) // 杭州 杭州 }

当访问结构体成员时会先在结构体中查找该字段,找不到再去嵌套的匿名字段中查找。嵌套可以多层嵌套,中途的匿名字段都可以省略。 注意:如果嵌套结构体内部有相同字段,那么匿名字段也不可省略。 模拟“继承”:外层结构体能够使用匿名嵌套结构体的方法。(Go语言没有继承的概念,但可以利用结构体模拟实现)

结构体字段可见性

结构体中字段大写开头表示可公开访问,小写表示私有(仅在定义当前结构体的包中可访问)。

JSON序列化和反序列化

JSON在线解析及格式化验证网站

JSON序列化

结构体–>JSON格式的字符串。 示例:

import ( "encoding/json" // 引入json包 "fmt" ) type house struct { Size int // 字段名首字母必须大写,否则json包访问不到字段数据 Style string } func main() { h1 := house{ 100, "中国风", } data, err := json.Marshal(h1) // 序列化函数 if err != nil { fmt.Println("json marshal failed") return } fmt.Printf("%s\n", data) // {"Size":100,"Style":"中国风"} }

注意:当结构体需要被其他包访问时,结构体字段(成员)名首字母必须大写

JSON反序列化

JSON格式的字符串–>结构体。 字符串中可以没有结构体的字段名,此时该字段值是对应类型的零值。 示例:

import ( "encoding/json" "fmt" ) type house struct { Size int Style string } func main() { str := `{"Size":100,"Style":"中国风"}` // JSON格式的字符串 var h2 house // 反序列化函数,参数是[]byte类型的JSON格式字符串和结构体指针(因为要对结构体变量进行修改) err = json.Unmarshal([]byte(str), &h2) if err != nil { fmt.Println("json unmarshal failed!") return } fmt.Printf("%#v\n", h2) // main.house{Size:100, Style:"中国风"} } 结构体标签(Tag)

Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。Tag在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:

`key1:"value1" key2:"value2"`

结构体Tag由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。同一个结构体字段可以设置多个键值对tag,不同的键值对之间使用空格分隔。 注意:同一个键值对之间不能加空格 在JSON序列化时,由于结构体字段名首字母必须大写,可能无法满足字段名首字母小写的需求,这时就需要使用Tag。示例如下:

import ( "encoding/json" // 引入json包 "fmt" ) type house struct { Size int `json:"size"` Style string `json:"style"` } func main() { h1 := house{ 100, "中国风", } data, err := json.Marshal(h1) // 序列化函数 if err != nil { fmt.Println("json marshal failed") return } fmt.Printf("%s\n", data) // {"size":100,"style":"中国风"} }

可以看到JSON序列化后的字符串中,字段名首字母是小写的。 参考1 参考2



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3