struct結構體
-
-
-
- 1.定義
- 2.匿名結構體
- 3.鍵值對初始化
- 4.構造函數
-
- 4.1 (值)方法和接收者
- 4.2 (指針)方法和接受者
- 4.3 結構體的“繼承
- 4.4 序列化與反序列化
- 4.5總結(知識點綜合使用案例:學生資訊管理)
-
-
注意:根據記憶體對齊原則,結構體裡面的資料類型,應根據類型所占的大小,依次排序,從小到大,越小越小前,主要是優化記憶體讀取速度。(取值是有一個”框“的(32 :4,64,:8),根據框取值時候是一塊一塊的取,超出框的部分,取兩次,并删除多餘的部分再和前面取得資料合并,操作變多了,消耗就多)
type Part1 struct {
a bool
b int32
c int8
d int64
e byte
}
type Part2 struct {
e byte
c int8
a bool
b int32
d int64
}
func main() {
part1 := Part1{}
part2 := Part2{}
fmt.Printf("part1 size: %d, align: %d\n", unsafe.Sizeof(part1), unsafe.Alignof(part1))
fmt.Printf("part2 size: %d, align: %d\n", unsafe.Sizeof(part2), unsafe.Alignof(part2))
}
輸出結果:
part1 size: 32, align: 8
part2 size: 16, align: 8
1.定義
Go語言中的基礎資料類型可以表示一些事物的基本屬性,但是當我們想表達一個事物的全部或部分屬性時,這時候再用單一的基本資料類型明顯就無法滿足需求了,Go語言提供了一種自定義資料類型,可以封裝多個基本資料類型,這種資料類型叫結構體,英文名稱
struct
。 也就是我們可以通過
struct
來定義自己的類型了。
Go語言中通過
struct
來實作面向對象。
注意:
- 類型名:辨別自定義結構體的名稱,在同一個包内不能重複。
- 字段名:表示結構體字段名。結構體中的字段名必須唯一。
- 字段類型:表示結構體字段的具體類型。
使用
type
和
struct
關鍵字來定義結構體,具體代碼格式如下:
type 類型名 struct {
字段名 字段類型
字段名 字段類型
…
}
舉個例子:
type person struct {
name string
city string
age int8
}
func main() {
var p1 person
p1.name = "張三"
p1.city = "北京"
p1.age = 18
fmt.Printf("p1=%v\n", p1) //p1={張三 北京 18}
fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"張三", city:"北京", age:18}
}
2.匿名結構體
注意:一般用于零時場景
var res struct{
name string
age int
}
res.name = “李四”
res.age = 19
fmt.Println(res)
3.鍵值對初始化
方式一:使用
&
對結構體進行取位址操作相當于對該結構體類型進行了一次
new
執行個體化操作
p3 := &person{}
fmt.Printf("%T\n", p3) //*main.person
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"", city:"", age:0}
p3.name = "七米"
p3.age = 30
p3.city = "成都"
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"七米", city:"成都", age:30}
方式二:
p5 := person{
name: "小王子",
city: "北京",
age: 18,
}
方式三:對結構體指針進行鍵值對初始化
p6 := &person{
name: "小王子",
city: "北京",
age: 18,
}
方式四:
p8 := &person{
"沙河娜紮",
"北京",
28,
}
fmt.Printf("p8=%#v\n", p8) //p8=&main.person{name:"沙河娜紮", city:"北京", age:28}
使用這種格式初始化時,需要注意:
- 必須初始化結構體的所有字段。
- 初始值的填充順序必須與字段在結構體中的聲明順序一緻。
- 該方式不能和鍵值初始化方式混用。
4.構造函數
作用:不用每次都初始化
注意:
構造函數都是以new開頭的;
傳回資料主要分結構體和結構體指針;
字段或者資料小的時候用結構體;
結構體比較打得時候用結構體指針,減少記憶體開銷
傳回結構體:
type persion struct {
name string
age int
}
func newP1 (x string ,y int) persion{
return persion{
name : x,
age : y,
}
}
func main(){
p2 := newP1(“張三”,13)
fmt.Printf("%#v",p2)
fmt.Println(p2)
}
4.1 (值)方法和接收者
Go語言中的
方法(Method)
是一種作用于特定類型變量的函數。這種特定類型變量叫做
接收者(Receiver)
。接收者的概念就類似于其他語言中的
this
或者
self
。
方法的定義格式如下:
func (接收者變量 接收者類型) 方法名(參數清單) (傳回參數) {
函數體
}
其中,
- 接收者變量:接收者中的參數變量名在命名時,官方建議使用接收者類型名稱首字母的小寫,而不是
、self
之類的命名。例如,this
類型的接收者變量應該命名為Person
,p
類型的接收者變量應該命名為Connector
等。c
- 接收者類型:接收者類型和參數類似,可以是指針類型和非指針類型。
- 方法名、參數清單、傳回參數:具體格式與函數定義相同。
舉個例子:
//Person 結構體
type Person struct {
name string
age int8
}
//NewPerson 構造函數
func NewPerson(name string, age int8) *Person {
return &Person{
name: name,
age: age,
}
}
//Dream Person做夢的方法
func (p Person) Dream() {
fmt.Printf("%s的夢想是學好Go語言!\n", p.name)
}
func main() {
p1 := NewPerson("小王子", 25)
p1.Dream()
}
4.2 (指針)方法和接受者
注意:
1.需要修改接收者中的值
2.接收者是拷貝代價比較大的大對象
3.保證一緻性,如果有某個方法使用了指針接收者,那麼其他的方法也應該使用指針接收者。
type persion struct {
name string
age int
}
func newP1(name string ,age int) persion {
return persion{
name: name,
age: age,
}
}
func ( p *****persion ) brithday(){
p.age++
fmt.Printf("%s 今年是 %d 歲了",p.name,p.age)
}
func main(){
p2 := newP1(“張三”,18)
p2.brithday()
fmt.Printf(”%s 今天 %d 歲了“,p2.name,p.age) // 張三今天19 歲了
}
4.3 結構體的“繼承
注意:在一個結構體裡面調用其他結構體,就可以使用其他結構體的方法
//Animal 動物
type Animal struct {
name string
}
func (a *Animal) move() {
fmt.Printf("%s會動!\n", a.name)
}
//Dog 狗
type Dog struct {
Feet int8
*Animal //通過嵌套匿名結構體實作繼承
}
func (d *Dog) wang() {
fmt.Printf("%s會汪汪汪~\n", d.name)
}
func main() {
d1 := &Dog{
Feet: 4,
Animal: &Animal{ //注意嵌套的是結構體指針
name: "樂樂",
},
}
d1.wang() //樂樂會汪汪汪~
d1.move() //樂樂會動!
}
4.4 序列化與反序列化
import (
“fmt”
"encoding/json"
)
type Persion struct{
Name string
json:"name"
// N大寫是外部包可以引用
Age int
josn:"age"
}
func main (){
a := Persion{
Name:“張三”,
Age:18,
}
data , err := json.Marshal(a) // 序列化
if err != nil{
fmt.Println(“this is error”)
return
}
fmt.Println(“下面是json”)
fmt.Println(string(data))
var a1 Persion
res :=
{"name":"張三","Age":18}
err = json.Unmarshal([]byte(res),&a1) // 反序列化,&a1 是取位址,不然隻是拷貝一個空
if err != nil{
fmt.Println(“this is err122”)
}
fmt.Println(“下面是反序列化”)
fmt.Printf("%#v",a1)
}
4.5總結(知識點綜合使用案例:學生資訊管理)
package main
import (
“fmt”
“os”
)
// 定義學生
type student struct {
id int64
name string
}
type sMangger struct{
allStudent map[int64]student
}
// 注意:變量不能存儲資料,隻是定義資料類型
var smr sMangger // 申明變量存儲學生管理資訊
// 展示學生資訊
func (m sMangger) showInfo(){
// fmt.Println(m)
for _ , v := range m.allStudent{
fmt.Printf("學号: %d , 姓名:%s\n", v.id , v.name)
}
}
func newStudent(id int64 , name string) student {
return student{
id:id,
name:name,
}
}
// 添加學生資訊
func (m sMangger) addInfo(id int64 , name string){
stu := newStudent(id,name)
m.allStudent[id] = stu
}
// 編輯
func (m sMangger) updateInfo(id int64){
data , ok := m.allStudent[id]
if !ok {
fmt.Println(“沒有這個玩意兒”)
return
}
fmt.Printf(“您要修改的學生資訊為:學号:%d 姓名:%s”, data.id , data.name)
fmt.Print(“請輸入您要修改的姓名”)
var xinName string
fmt.Scan(&xinName)
data.name = xinName // 指派
m.allStudent[id] = data // 更新
}
// 删除
func (m sMangger) deleteInfo(id int64){
data , ok := m.allStudent[id]
if !ok {
fmt.Println(“沒有這個人喲~~”)
return
}
fmt.Printf(“學生資訊為:學号;%d 姓名:%s”, data.id , data.name)
fmt.Println(“确定要删除嗎? 1:确定 0:取消”)
var xinNum int64
fmt.Scan(&xinNum)
delete(m.allStudent,id)
}
func main(){
var (
num int64
id int64
name string
isOk int64
)
smr = sMangger{
allStudent: make(map[int64]student,100),
}
for {
// 選擇項目
fmt.Print(`
我們提供一下集中選項(請輸入編号進行操作):
1.檢視學生資訊;
2.添加學生資訊;
3.編輯學生資訊;
4.删除學生資訊;
請選擇: `)
// 接受使用者的輸入的選項服務
fmt.Scan(&num)
// 判斷執行要執行的動作
switch num{
case 1:
fmt.Println("您選擇了1 檢視學生資訊")
smr.showInfo()
case 2:
fmt.Println("您選擇了2 添加學生資訊")
fmt.Print("請輸入學生學号 ")
fmt.Scan(&id)
fmt.Print("請輸入學生姓名 ")
fmt.Scan(&name)
fmt.Printf("您确定這是要添加的學生資訊嗎?學号: %d 姓名: %s ,1:确定 0:取消 ",id,name)
fmt.Scan(&isOk)
if isOk == 1 {
// fmt.Println("ok")
// 執行邏輯
// add :=
smr.addInfo(id,name)
}else{
fmt.Println("cannl")
os.Exit(1)
}
case 3:
fmt.Println("您選擇了3 編輯學生資訊")
fmt.Print("請輸入學号:")
fmt.Scan(&id)
smr.updateInfo(id)
case 4:
fmt.Println("您選擇了4 删除學生資訊")
fmt.Print("請輸入學号:")
fmt.Scan(&id)
smr.deleteInfo(id)
default:
fmt.Println("目前沒有此選項服務喲")
fmt.Println("很高興為您服務")
os.Exit(1)
}
}
}