大家對(duì)golang中結(jié)構(gòu)體的了解可能停留在概念的層面上,而對(duì)于golang中結(jié)構(gòu)體的使用方法了解相對(duì)較少。今天就跟大家聊聊golang中結(jié)構(gòu)體的使用。
成都創(chuàng)新互聯(lián)是專(zhuān)業(yè)的順河網(wǎng)站建設(shè)公司,順河接單;提供成都網(wǎng)站制作、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專(zhuān)業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行順河網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專(zhuān)業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專(zhuān)業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!在Go語(yǔ)言中有一些基本的數(shù)據(jù)類(lèi)型,如string,整型,浮點(diǎn)型,布爾等數(shù)據(jù)類(lèi)型,Go語(yǔ)言中可以使用type關(guān)鍵字來(lái)定義自定義類(lèi)型。
自定義類(lèi)型是定義了一個(gè)全新的類(lèi)型。我們可以基于內(nèi)置的基本類(lèi)型定義,也可以通過(guò)struct定義。
//將MyInt定義為int類(lèi)型
type MyInt int
通過(guò)Type關(guān)鍵字的定義,MyInt就是一種新的類(lèi)型,它具有int的特性。
類(lèi)型別名是Go1.9版本添加的新功能。
類(lèi)型別名規(guī)定:TypeAlias只是Type的別名,本質(zhì)上TypeAlias與Type是同一個(gè)類(lèi)型。就像我們的英文名,乳名,但這些名字都指的是一個(gè)人。
type TypeAlias = type
我們之前見(jiàn)過(guò)的rune和byte都是類(lèi)型別名,他們的定義如下:
type byte = uint8
type rune = int32
類(lèi)型別名與類(lèi)型定義,表面上看只有一個(gè)等號(hào)的差異,我們可以通過(guò)下面的代碼來(lái)查看他們的區(qū)別。
package main
import "fmt"
type NewInt int
type MyInt = int
func main() {
var a NewInt
var b MyInt
fmt.Printf("type of a:%T\n",a)
fmt.Printf("type of b:%T\n",b)
}
結(jié)果:
type of a:main.NewInt
type of b:int
Process finished with exit code 0
結(jié)果顯示a的類(lèi)型是main.NewInt,表示main包下定義的NewInt類(lèi)型。
b類(lèi)型是int。MyInt類(lèi)型只會(huì)在代碼中存在,編譯完成時(shí)并不會(huì)有MyInt類(lèi)型。
Go語(yǔ)言中的基本數(shù)據(jù)類(lèi)型可以表示一些事物的基本屬性,但是當(dāng)我們想表達(dá)一個(gè)事物的全部或部分屬性時(shí),這時(shí)候基本數(shù)據(jù)類(lèi)型就無(wú)法滿(mǎn)足需求了。
Go語(yǔ)言提供了一種自定義數(shù)據(jù)類(lèi)型,可以封裝多個(gè)基本數(shù)據(jù)類(lèi)型,這種數(shù)據(jù)類(lèi)型叫結(jié)構(gòu)體(struct)。
我們可以通過(guò)struct來(lái)定義自己的類(lèi)型了。
Go語(yǔ)言中通過(guò)struct來(lái)實(shí)現(xiàn)面向?qū)ο蟆?/code>
使用type和struct關(guān)鍵字來(lái)定義結(jié)構(gòu)體,具體代碼格式如下:
type 類(lèi)型名 struct {
字段名 字段類(lèi)型
字段名 字段類(lèi)型
…
}
其中:
類(lèi)型名:標(biāo)識(shí)自定義結(jié)構(gòu)體的名稱(chēng),在同一個(gè)包內(nèi)不能重復(fù)。
字段名:表示結(jié)構(gòu)體字段名。結(jié)構(gòu)體中的字段名必須唯一。
字段類(lèi)型:表示結(jié)構(gòu)體字段的具體類(lèi)型。
舉個(gè)例子,我們定義一個(gè)Person結(jié)構(gòu)體,代碼如下:
type Person struct {
name string
city string
age int8
}
同樣類(lèi)型的字段可以卸載一行
type Person struct {
name,city string
age int8
}
這樣我們就擁有了一個(gè)Person的自定義類(lèi)型,它有name,city,age三個(gè)字段,分別表示姓名,城市和年齡。
這樣我們就能使用Person結(jié)構(gòu)體存儲(chǔ)人的信息了。
語(yǔ)言?xún)?nèi)置的數(shù)據(jù)類(lèi)型是用來(lái)描述一個(gè)值得,結(jié)構(gòu)體是用來(lái)描述一組值的。
比如一個(gè)人有名字,年齡和居住城市等,本質(zhì)上是一種聚合型的數(shù)據(jù)類(lèi)型。
只有當(dāng)結(jié)構(gòu)體實(shí)例化時(shí),才會(huì)真正的分配內(nèi)存。即必須實(shí)例化后才能使用結(jié)構(gòu)體的字段。
結(jié)構(gòu)體本身也是一種類(lèi)型,我們可以像聲明內(nèi)置類(lèi)型一樣使用var關(guān)鍵字聲明結(jié)構(gòu)體類(lèi)型。
var 結(jié)構(gòu)體實(shí)例 結(jié)構(gòu)體類(lèi)型
通過(guò)"."來(lái)訪(fǎng)問(wèn)結(jié)構(gòu)體的字段,例如person1.name和person1.age
package main
import "fmt"
type Person struct {
name,city string
age int8
}
func main() {
var person1 Person
person1.name="vita"
person1.city="ShangHai"
person1.age=27
fmt.Printf("p1=%v\n",person1)
fmt.Printf("p1=%#v\n",person1)
}
結(jié)果:
p1={vita ShangHai 27}
p1=main.Person{name:"vita", city:"ShangHai", age:27}
Process finished with exit code 0
在定義一些臨時(shí)數(shù)據(jù)結(jié)構(gòu)時(shí),可以使用匿名結(jié)構(gòu)體。
package main
import "fmt"
func main() {
var person2 struct{name string;age int}
person2.name="vita"
person2.age=27
fmt.Printf("p1=%v\n",person2)
fmt.Printf("p1=%#v\n",person2)
}
結(jié)果:
p1={vita 27}
p1=struct { name string; age int }{name:"vita", age:27}
Process finished with exit code 0
我們還可以通過(guò)new關(guān)鍵字對(duì)結(jié)構(gòu)體進(jìn)行實(shí)例化,得到的是結(jié)構(gòu)體的地址。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func main() {
var person3 = new(Person)
fmt.Printf("%T\n",person3)
fmt.Printf("p3=%#v\n",person3)
person3.name="vita"
person3.age=27
fmt.Printf("p3=%v\n",person3)
fmt.Printf("p3=%#v\n",person3)
}
結(jié)果:
*main.Person
p3=&main.Person{name:"", city:"", age:0}
p3=&{vita 27}
p3=&main.Person{name:"vita", city:"", age:27}
Process finished with exit code 0
從打印結(jié)果可以看到,p3是一個(gè)結(jié)構(gòu)體指針。
Go語(yǔ)言中支持對(duì)結(jié)構(gòu)體指針直接使用"."訪(fǎng)問(wèn)結(jié)構(gòu)體成員。
使用&對(duì)結(jié)構(gòu)體進(jìn)行取地址操作相當(dāng)于對(duì)該結(jié)構(gòu)體進(jìn)行了一次new實(shí)例化操作。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func main() {
var person4 = &Person{}
fmt.Printf("%T\n",person4)
fmt.Printf("p4=%#v\n",person4)
person4.name="vita"
person4.age=27
fmt.Printf("p4=%v\n",person4)
fmt.Printf("p4=%#v\n",person4)
}
結(jié)果:
*main.Person
p4=&main.Person{name:"", city:"", age:0}
p4=&{vita 27}
p4=&main.Person{name:"vita", city:"", age:27}
Process finished with exit code 0
person4.name="vita"其實(shí)在底層是(* person4).name="vita",這是Go語(yǔ)言幫我們實(shí)現(xiàn)的語(yǔ)法糖。
沒(méi)有初始化的結(jié)構(gòu)體,其成員變量都是對(duì)應(yīng)類(lèi)型的零值。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func main() {
var p1 Person
fmt.Printf("%T\n",p1)
fmt.Printf("p1=%v\n",p1)
fmt.Printf("p1=%#v\n",p1)
}
結(jié)果:
main.Person
p1={ 0}
p1=main.Person{name:"", city:"", age:0}
Process finished with exit code 0
使用鍵值對(duì)對(duì)結(jié)構(gòu)體初始化時(shí),鍵對(duì)應(yīng)結(jié)構(gòu)體的字段,值對(duì)應(yīng)該字段的初始值。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func main() {
var p1 = Person{
name:"vita",
city:"ShangHai",
age:27,
}
fmt.Printf("%T\n",p1)
fmt.Printf("p1=%v\n",p1)
fmt.Printf("p1=%#v\n",p1)
}
結(jié)果:
main.Person
p1={vita ShangHai 27}
p1=main.Person{name:"vita", city:"ShangHai", age:27}
Process finished with exit code 0
也可以對(duì)結(jié)構(gòu)體指針進(jìn)行鍵值對(duì)初始化
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func main() {
var p1 = &Person{
name:"vita",
city:"ShangHai",
age:27,
}
fmt.Printf("%T\n",p1)
fmt.Printf("p1=%v\n",p1)
fmt.Printf("p1=%#v\n",p1)
}
結(jié)果:
*main.Person
p1=&{vita ShangHai 27}
p1=&main.Person{name:"vita", city:"ShangHai", age:27}
Process finished with exit code 0
某些字段沒(méi)有初始值的時(shí)候,該字段可以不寫(xiě)。沒(méi)有指定初始值的字段值就是該字段類(lèi)型的零值。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func main() {
var p1 = &Person{
name:"vita",
}
fmt.Printf("%T\n",p1)
fmt.Printf("p1=%v\n",p1)
fmt.Printf("p1=%#v\n",p1)
}
結(jié)果:
*main.Person
p1=&{vita 0}
p1=&main.Person{name:"vita", city:"", age:0}
Process finished with exit code 0
初始化結(jié)構(gòu)體的時(shí)候可以簡(jiǎn)寫(xiě),也就是初始化的時(shí)候不寫(xiě)鍵,直接寫(xiě)值
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func main() {
var p1 = &Person{
"vita",
"ShangHai",
27,
}
fmt.Printf("%T\n",p1)
fmt.Printf("p1=%v\n",p1)
fmt.Printf("p1=%#v\n",p1)
}
結(jié)果:
*main.Person
p1=&{vita ShangHai 27}
p1=&main.Person{name:"vita", city:"ShangHai", age:27}
Process finished with exit code 0
使用這種格式初始化時(shí),需要注意:
1.必須初始化結(jié)構(gòu)體的所有字段。
2.初始值的填充順序必須與字段在結(jié)構(gòu)體中的聲明順序一致。
3.該方式不能和鍵值初始化方式混用。
結(jié)構(gòu)體占用一塊連續(xù)的內(nèi)存。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func main() {
var p1 = &Person{
"vita",
"ShangHai",
27,
}
fmt.Printf("p1.name %p\n",&p1.name)
fmt.Printf("p1.city %p\n",&p1.city)
fmt.Printf("p1.age %p\n",&p1.age)
}
結(jié)果:
p1.name 0xc00005c360
p1.city 0xc00005c370
p1.age 0xc00005c380
Process finished with exit code 0
// 內(nèi)存是以字節(jié)為單位的十六進(jìn)制數(shù)
// 1字節(jié) = 8位 = 8bit
package main
import "fmt"
type test struct {
a int8
b int8
c int8
}
func main() {
var p1 = &test{
1,2,3,
}
fmt.Printf("p1.a %p\n",&p1.a)
fmt.Printf("p1.b %p\n",&p1.b)
fmt.Printf("p1.c %p\n",&p1.c)
}
結(jié)果:
p1.a 0xc000054080
p1.b 0xc000054081
p1.c 0xc000054082
Process finished with exit code 0
Go語(yǔ)言的結(jié)構(gòu)體沒(méi)有構(gòu)造函數(shù),可以自己實(shí)現(xiàn)。
下面的代碼就實(shí)現(xiàn)了一個(gè)Person的構(gòu)造函數(shù)。因?yàn)閟truct是值類(lèi)型,如果結(jié)構(gòu)體比較復(fù)雜的話(huà),值拷貝性能開(kāi)銷(xiāo)會(huì)比較大,所以該構(gòu)造函數(shù)返回的是結(jié)構(gòu)體指針類(lèi)型。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
//構(gòu)造函數(shù)
func newPerson(name,city string,age int) *Person {
return &Person{
name: name,
city: city,
age: age,
}
}
func main() {
//調(diào)用構(gòu)造函數(shù)
p := newPerson("vita","ShangHai",27)
fmt.Printf("%#v",p)
}
結(jié)果:
&main.Person{name:"vita", city:"ShangHai", age:27}
Process finished with exit code 0
Go語(yǔ)言中的方法(method)是一種作用于特定類(lèi)型變量的函數(shù)。這種特定類(lèi)型變量叫做"接收者(Receiver)"。
接收者的概念就類(lèi)似于其他語(yǔ)言中的this或者self。
方法的定義格式如下:
func (接收者變量 接收者類(lèi)型) 方法名(參數(shù)列表) (返回參數(shù)){
函數(shù)體
}
其中,
接收者變量:接收者中的參數(shù)變量名在命名的時(shí)候,官方建議使用接收者類(lèi)型名的第一個(gè)小寫(xiě)字母,而不是self,this之類(lèi)的命名。
例如:Person類(lèi)型的接收者變量應(yīng)該命名為p,Connector類(lèi)型的接收者變量應(yīng)該命名為c等。
接收者類(lèi)型:接收者類(lèi)型和參數(shù)類(lèi)似,可以是指針類(lèi)型和非指針類(lèi)型。
方法名,參數(shù)列表,返回參數(shù):具體格式與函數(shù)定義相同。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func newPerson(name,city string,age int) *Person {
return &Person{
name: name,
city: city,
age: age,
}
}
func (p Person) Dream() {
fmt.Printf("%s的夢(mèng)想是實(shí)現(xiàn)自己的價(jià)值。",p.name)
}
func main() {
p := newPerson("vita","ShangHai",27)
p.Dream()
}
結(jié)果:
vita的夢(mèng)想是實(shí)現(xiàn)自己的價(jià)值。
Process finished with exit code 0
方法與函數(shù)的區(qū)別是,函數(shù)不屬于任何類(lèi)型,方法屬于特定的類(lèi)型。
指針類(lèi)型的接收者由一個(gè)結(jié)構(gòu)體的指針組成,由于指針的特性,調(diào)用方法時(shí)修改接收者指針的任意成員變量,在方法結(jié)束后,修改都是有效的。
這種方式接近于其他語(yǔ)言中的this或者self。下面我們?yōu)镻erson添加一個(gè)SetAge方法,修改實(shí)例變量的年齡。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func newPerson(name,city string,age int) *Person {
return &Person{
name: name,
city: city,
age: age,
}
}
func (p Person) Dream() {
fmt.Printf("%s的夢(mèng)想是實(shí)現(xiàn)自己的價(jià)值。",p.name)
}
//指針類(lèi)型的接收者
func (p *Person) SetAge(newAge int) {
p.age=newAge
}
func main() {
p := newPerson("vita","ShangHai",27)
fmt.Println(p.age)
//修改年齡
p.SetAge(29)
fmt.Println(p.age)
}
結(jié)果:
27
29
Process finished with exit code 0
當(dāng)方法作用于值類(lèi)型的接收者時(shí),GO語(yǔ)言會(huì)在代碼運(yùn)行時(shí)將接收者的值復(fù)制一份。
在值類(lèi)型接收者的方法中,可以獲取接收者的成員值,但是修改只是針對(duì)副本,無(wú)法修改接收者變量本身。
package main
import "fmt"
type Person struct {
name string
city string
age int
}
func newPerson(name,city string,age int) *Person {
return &Person{
name: name,
city: city,
age: age,
}
}
func (p Person) Dream() {
fmt.Printf("%s的夢(mèng)想是實(shí)現(xiàn)自己的價(jià)值。",p.name)
}
//值類(lèi)型的接收者
func (p Person) SetAge(newAge int) {
p.age=newAge
}
func main() {
p := newPerson("vita","ShangHai",27)
fmt.Println(p.age)
//修改年齡
p.SetAge(29)
fmt.Println(p.age)
}
結(jié)果:
27
27
Process finished with exit code 0
1.需要修改接收者中的值。
2.接收者是拷貝代價(jià)比較大的大對(duì)象。
3.保證一致性,如果有某個(gè)方法使用了指針接收者,那么其他的方法也應(yīng)該使用指針接收者。
在GO語(yǔ)言中,接收者的類(lèi)型可以是任何類(lèi)型,不僅僅是結(jié)構(gòu)體,任何類(lèi)型都可以擁有方法。
舉個(gè)例子,我們基于內(nèi)置的int類(lèi)型,使用type關(guān)鍵字可以定義新的自定義類(lèi)型,然后為我們的自定義類(lèi)型添加方法。
package main
import "fmt"
type MyInt int
func (m MyInt) SayHello() {
fmt.Println("hello,我是一個(gè)Int")
}
func main() {
var m MyInt
m.SayHello()
m=100
fmt.Printf("%#v %T\n",m,m)
}
結(jié)果:
hello,我是一個(gè)Int
100 main.MyInt
Process finished with exit code 0
注意:
非本地類(lèi)型不能定義方法,即不能給別的包的類(lèi)型定義方法。
結(jié)構(gòu)體允許其成員字段在聲明時(shí)沒(méi)有字段名,只有字段類(lèi)型,這種沒(méi)有名字的字段稱(chēng)為匿名字段。
匿名字段默認(rèn)采用類(lèi)型名作為字段名,結(jié)構(gòu)體要求字段名必須唯一,因此結(jié)構(gòu)體中同種類(lèi)型的匿名字段只能有一個(gè)。
package main
import "fmt"
type Person struct {
string
int
}
func main() {
p1:=Person{
"vita",
27,
}
fmt.Printf("%#v\n",p1)
fmt.Println(p1.string,p1.int)
}
結(jié)果:
main.Person{string:"vita", int:27}
vita 27
Process finished with exit code 0
一個(gè)結(jié)構(gòu)體中可以嵌套另一個(gè)結(jié)構(gòu)體或結(jié)構(gòu)體指針。
package main
import "fmt"
//地址結(jié)構(gòu)體
type Address struct {
Province string
City string
}
//User結(jié)構(gòu)體
type User struct {
Name string
Gender string
Address Address
}
func main() {
user1 := User{
Name:"vita",
Gender:"女",
Address:Address{
Province:"ShangHai",
City:"ShangHai",
},
}
fmt.Printf("user1=%#v\n",user1)
}
結(jié)果:
user1=main.User{Name:"vita", Gender:"女", Address:main.Address{Province:"ShangHai", City:"ShangHai"}}
Process finished with exit code 0
當(dāng)訪(fǎng)問(wèn)結(jié)構(gòu)體成員時(shí),會(huì)現(xiàn)在結(jié)構(gòu)體中查找該字段,找不到就去匿名結(jié)構(gòu)體中查找。
package main
import "fmt"
//地址結(jié)構(gòu)體
type Address struct {
Province string
City string
}
//User結(jié)構(gòu)體
type User struct {
Name string
Gender string
Address
}
func main() {
var user2 User
user2.Name = "vita"
user2.Gender = "女"
user2.Address.Province = "江蘇" //通過(guò)匿名結(jié)構(gòu)體.字段名訪(fǎng)問(wèn)
user2.City = "南京" //直接訪(fǎng)問(wèn)匿名結(jié)構(gòu)體的字段名
fmt.Printf("user1=%#v\n",user2)
}
結(jié)果:
user1=main.User{Name:"vita", Gender:"女", Address:main.Address{Province:"江蘇", City:"南京"}}
Process finished with exit code 0
嵌套結(jié)構(gòu)體內(nèi)部可能存在相同的字段名。這時(shí)候?yàn)榱吮苊馄缌x,需要指定具體的內(nèi)嵌結(jié)構(gòu)體的字段
package main
//Address 地址結(jié)構(gòu)體
type Address struct {
Province string
City string
CreateTime string
}
//Email 郵箱結(jié)構(gòu)體
type Email struct {
Account string
CreateTime string
}
//User 用戶(hù)結(jié)構(gòu)體
type User struct {
Name string
Gender string
Address
Email
}
func main() {
var user3 User
user3.Name = "沙河娜扎"
user3.Gender = "男"
// user3.CreateTime = "2019" //ambiguous selector user3.CreateTime
user3.Address.CreateTime = "2000" //指定Address結(jié)構(gòu)體中的CreateTime
user3.Email.CreateTime = "2000" //指定Email結(jié)構(gòu)體中的CreateTime
}
Go語(yǔ)言中使用結(jié)構(gòu)體也可以實(shí)現(xiàn)其他語(yǔ)言中面向?qū)ο蟮睦^承。
//Animal 動(dòng)物
type Animal struct {
name string
}
func (a *Animal) move() {
fmt.Printf("%s會(huì)動(dòng)!\n", a.name)
}
//Dog 狗
type Dog struct {
Feet int8
*Animal //通過(guò)嵌套匿名結(jié)構(gòu)體實(shí)現(xiàn)繼承
}
func (d *Dog) wang() {
fmt.Printf("%s會(huì)汪汪汪~(yú)\n", d.name)
}
func main() {
d1 := &Dog{
Feet: 4,
Animal: &Animal{ //注意嵌套的是結(jié)構(gòu)體指針
name: "樂(lè)樂(lè)",
},
}
d1.wang() //樂(lè)樂(lè)會(huì)汪汪汪~(yú)
d1.move() //樂(lè)樂(lè)會(huì)動(dòng)!
}
結(jié)構(gòu)體中字段大寫(xiě)開(kāi)頭表示可公開(kāi)訪(fǎng)問(wèn),小寫(xiě)表示私有(僅在定義當(dāng)前結(jié)構(gòu)體的包中可訪(fǎng)問(wèn))。
JSON數(shù)據(jù)是一些鍵值對(duì)數(shù)據(jù),便于閱讀和編寫(xiě)。
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
ID int
Gender string
Name string
}
type Class struct {
Title string
Students []*Student
}
func main() {
c:=&Class{
Title: "101",
Students: make([]*Student,0,200),
}
for i:=0;i<10;i++{
stu := &Student{
ID: i,
Gender: "男",
Name: "張三",
}
c.Students = append(c.Students,stu)
}
//JSON序列化:結(jié)構(gòu)體--》JSON格式的字符串
data,err := json.Marshal(c)
if err != nil{
fmt.Println("json marshal failed")
return
}
fmt.Printf("json:%s\n",data)
//JSON反序列化:JSON格式的字符串--》結(jié)構(gòu)體
str := `{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"stu00"},{"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}`
c1 := &Class{}
err = json.Unmarshal([]byte(str),c1)
if err != nil{
fmt.Println("json unmarshal failed!")
return
}
fmt.Printf("%#v\n",c1)
}
結(jié)果:
json:{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"張三"},{"ID":1,"Gender":"男","Name":"張三"},{"ID":2,"Gender":"男","Name":"張三"},{"ID":3,"Gender":"男","Name":"張三"},{"ID":4,"Gender":"男","Name":"張三"},{"ID":5,"Gender":"男","Name":"張三"},{"ID":6,"Gender":"男","Name":"張三"},{"ID":7,"Gender":"男","Name":"張三"},{"ID":8,"Gender":"男","Name":"張三"},{"ID":9,"Gender":"男","Name":"張三"}]}
&main.Class{Title:"101", Students:[]*main.Student{(*main.Student)(0xc0000526f0), (*main.Student)(0xc000052720), (*main.Student)(0xc000052750), (*main.Student)(0xc000052780), (*main.Student)(0xc0000527e0), (*main.Student)(0xc000052810), (*main.Student)(0xc000052840), (*main.Student)(0xc000052870), (*main.Student)(0xc0000528a0), (*main.Student)(0xc0000528d0)}}
Process finished with exit code 0
Tag是結(jié)構(gòu)體的元信息,可以在運(yùn)行的時(shí)候通過(guò)反射的 機(jī)制讀取出來(lái)。
Tag在結(jié)構(gòu)體字段的后方定義,由一對(duì)反引號(hào)包裹起來(lái),具體格式如下:
`key1:"value1" key2:"value2"`
結(jié)構(gòu)體標(biāo)簽由一個(gè)或多個(gè)鍵值對(duì)組成。鍵和值使用冒號(hào)分隔,值用引號(hào)括起來(lái)。
鍵值對(duì)質(zhì)檢使用一個(gè)空格分隔,
注意事項(xiàng):
1.為結(jié)構(gòu)體編寫(xiě)Tag時(shí),必須嚴(yán)格遵守鍵值對(duì)的規(guī)則。
2.結(jié)構(gòu)體標(biāo)簽的解析代碼的容錯(cuò)能力很差,一旦格式寫(xiě)錯(cuò),編譯和運(yùn)行時(shí)都不會(huì)提示任何錯(cuò)誤,通過(guò)反射也無(wú)法正確取值。
3.key和value之間是不可以有空格的。
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
ID int `json:"id"` //通過(guò)指定tag實(shí)現(xiàn)json序列化該字段時(shí)的key
Gender string //json序列化是默認(rèn)使用字段名作為key
name string //私有不能被json包訪(fǎng)問(wèn)
}
func main() {
s1 := Student{
ID: 1,
Gender: "男",
name: "沙河娜扎",
}
data,err := json.Marshal(s1)
if err != nil{
fmt.Println("json marshal failed!")
return
}
fmt.Printf("json str:%s\n",data)
}
結(jié)果:
json str:{"id":1,"Gender":"男"}
Process finished with exit code 0
package main
import (
"fmt"
"os"
)
// 1. 打印菜單
// 2. 等待用戶(hù)輸入菜單選項(xiàng)
// 3. 添加書(shū)籍的函數(shù)
// 4. 修改書(shū)籍的函數(shù)
// 5. 展示書(shū)籍的函數(shù)
// 6. 退出 os.Exit(0)
type Book struct {
title string
author string
price float32
publish bool
}
var(
AllBooks []*Book
)
func showMenu() {
fmt.Println("1.展示所有書(shū)籍")
fmt.Println("2.添加書(shū)籍")
fmt.Println("3.修改書(shū)籍")
fmt.Println("4.刪除書(shū)籍")
fmt.Println("5.退出")
fmt.Println()
}
func showAllBook() {
fmt.Println("書(shū)籍信息如下:")
for _,value := range AllBooks{
fmt.Printf("title:%s author:%s price:%.2f publish:%v",value.title,value.author,value.price,value.publish)
}
fmt.Println()
}
func newBook(title,author string,price float32,publish bool) *Book {
return &Book{
title:title,
author:author,
price:price,
publish:publish,
}
}
func addBook() {
var (
title string
author string
price float32
publish bool
)
fmt.Println("輸入書(shū)籍的title(string),author(string),price(float32),publish(bool)信息")
fmt.Scanln(&title,&author,&price,&publish)
for _,value := range AllBooks{
if value.title == title{
fmt.Println("該書(shū)已經(jīng)存在了!")
return
}
}
book := newBook(title,author,price,publish)
AllBooks = append(AllBooks,book)
}
func modifyBook() {
fmt.Println("輸入要修改的書(shū)籍信息")
var (
title string
author string
price float32
publish bool
)
fmt.Println("輸入書(shū)籍的title(string),author(string),price(float32),publish(bool)信息")
fmt.Scanln(&title,&author,&price,&publish)
for index,value := range AllBooks{
if value.title == title{
modifyBook := newBook(title,author,price,publish)
AllBooks[index] = modifyBook
fmt.Println("書(shū)籍信息修改成功!")
return
}
}
fmt.Println("該書(shū)不存在,就不進(jìn)行修改了!")
}
func delBook() {
var (
title string
)
fmt.Println("輸入要?jiǎng)h除的書(shū)籍名稱(chēng)")
fmt.Scanln(&title)
for index,value := range AllBooks{
if value.title == title{
// 要?jiǎng)h除索引為2的元素
AllBooks = append(AllBooks[:index], AllBooks[index+1:]...)
fmt.Println("書(shū)籍刪除成功!")
return
}
}
fmt.Println("該書(shū)不存在!")
}
func main() {
for{
showMenu()
var input int
fmt.Scanln(&input)
switch input {
case 1:
showAllBook()
case 2:
addBook()
case 3:
modifyBook()
case 4:
delBook()
case 5:
os.Exit(0)
}
}
}
結(jié)果:
1.展示所有書(shū)籍
2.添加書(shū)籍
3.修改書(shū)籍
4.刪除書(shū)籍
5.退出
1
書(shū)籍信息如下:
1.展示所有書(shū)籍
2.添加書(shū)籍
3.修改書(shū)籍
4.刪除書(shū)籍
5.退出
2
輸入書(shū)籍的title(string),author(string),price(float32),publish(bool)信息
zhangsan zhangsan 12.23 true
1.展示所有書(shū)籍
2.添加書(shū)籍
3.修改書(shū)籍
4.刪除書(shū)籍
5.退出
3
輸入要修改的書(shū)籍信息
輸入書(shū)籍的title(string),author(string),price(float32),publish(bool)信息
zhangsan Zhansan 231.1 false
書(shū)籍信息修改成功!
1.展示所有書(shū)籍
2.添加書(shū)籍
3.修改書(shū)籍
4.刪除書(shū)籍
5.退出
1
書(shū)籍信息如下:
title:zhangsan author:Zhansan price:231.10 publish:false
1.展示所有書(shū)籍
2.添加書(shū)籍
3.修改書(shū)籍
4.刪除書(shū)籍
5.退出
4
輸入要?jiǎng)h除的書(shū)籍名稱(chēng)
zhangsan
書(shū)籍刪除成功!
1.展示所有書(shū)籍
2.添加書(shū)籍
3.修改書(shū)籍
4.刪除書(shū)籍
5.退出
1
書(shū)籍信息如下:
1.展示所有書(shū)籍
2.添加書(shū)籍
3.修改書(shū)籍
4.刪除書(shū)籍
5.退出
5
Process finished with exit code 0
上文描述的就是golang中結(jié)構(gòu)體的詳細(xì)內(nèi)容,具體使用情況還需要大家自己動(dòng)手實(shí)驗(yàn)使用過(guò)才能領(lǐng)會(huì)。如果想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線(xiàn),公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。