Golang——結構體struct

Go語言中沒有“類”的改變,不支持類的“繼承”等面向對象概念鹦聪。Go語言中通過結構體的內(nèi)嵌再配合接口比面向對象更具有更高的擴展性和靈活性账阻。

自定義類型和類型別名

自定義類型:新類型,可以基于內(nèi)置的基本類型定義泽本,也可以通過stuct定義宰僧;
類型別名:只存在代碼編寫過程中,編碼編譯字后就不存在观挎,增加提高代碼可讀性琴儿;例如,byteunit8的類型別名嘁捷,runeint32的類型別名造成。

//自定義類型
// NewInt 是一個新類型,具有int的特性
type NewInt int

//類型別名
type MyInt = int

func main() {
    var a NewInt
    fmt.Println(a)          //0
    fmt.Printf("%T\n", a)   //main.NewInt

    var b MyInt
    fmt.Println(b)          //0
    fmt.Printf("%T\n", b)   //int
} 

結構體

結構體struct是一種自定義類型雄嚣,可以封裝多個基本數(shù)據(jù)類型晒屎。
結構體是值類型。
結構體在內(nèi)存中是連續(xù)在一塊的缓升。
結構體中字段大寫字母開頭表示可公開訪問鼓鲁,小寫字母表示私有(僅在定義當前結構體的包中可訪問)。

//創(chuàng)建新的類型需要用type關鍵字
type student struct {
    name string
    age int
    gender string
    hobby []string
}

func main() {

    var stu = student{
        name : "張三",
        age : 20,
        gender : "男",
        hobby : []string{"籃球", "足球", "乒乓球"},
    }
    fmt.Println(stu)   // {張三 20 男 [籃球 足球 乒乓球]}

    //采用.屬性方式訪問
    fmt.Println(stu.name)
    fmt.Println(stu.age)
    fmt.Println(stu.gender)
    fmt.Println(stu.hobby)

    //struct是值類型港谊,如果初始化沒有設置值骇吭,則屬性是默認值
    var lisi = student{}
    fmt.Println(lisi)  //{ 0  []}

    //使用new關鍵字進行聲明(實例化),得到結構體指針
    var wangwu = new(student)
    // (*wangwu).name
    wangwu.name = "王五"
    wangwu.age = 18
    fmt.Println(wangwu)  //&{王五 18  []}

    //聲明(實例化)歧寺,得到結構體指針
    var aaa = &student{}
    fmt.Println(aaa)     //&{ 0  []}
    
    //初始化
    //只用值的燥狰,需要所有屬性都要初始化
    var bbb = student{
        "bbb",
        18,
        "男",
        []string{"a", "b"},
    }
    fmt.Println(bbb)   //{bbb 18 男 [a b]}

    //初始化,得到結構體指針
    //key-value格式斜筐,不需要所有的屬性都初始化
    var ccc = &student{
        name : "ccc",
        age : 18,
    }
    fmt.Println(ccc)   //&{ccc 18  []}
    
}

同樣類型的字段可以寫在一行

type student struct {
    id int
    name,city string
}

自己實現(xiàn)構造函數(shù)

//創(chuàng)建新的類型需要用type關鍵字
type student struct {
    name string
    age int
    gender string
    hobby []string
}

//實現(xiàn)一個構造函數(shù)龙致,習慣上new加類型名
func newStudent(name string, age int, gender string, hobby []string) *student {
    return &student{
        name: name,
        age: age,
        gender: gender,
        hobby: hobby,
    }
}

func main() {

    hobby := []string{"a", "b"}
    stu := newStudent("zhang", 18, "男", hobby)
    fmt.Println(stu.name)
    fmt.Println(stu.age)
    fmt.Println(stu.gender)
    fmt.Println(stu.hobby)
    
}

匿名結構體

    var user struct{Name string; Age int}
    user.Name = "張三"
    user.Age = 18
    fmt.Printf("%#v\n", user)

方法和接受者

Go語言中的方法method是一種作用于特定類型變量的函數(shù)。這種特定類型變量叫做接受者(Receiver)顷链,類似于其它語言中的this或者self目代。
函數(shù)是誰都可以調(diào)用的。
方法就是某個具體的類型才能調(diào)用的函數(shù)嗤练。

func (接受者變量 接受者類型) 方法名(參數(shù)列表) (返回參數(shù)){
    函數(shù)體
}

其中:

  • 接受者變量:參數(shù)變量名在命名時候榛了,官方建議使用接受者類型名的第一個小寫字母,而不是self潭苞、this
  • 接受者類型:可以是指針類型和非指針類型忽冻,一般情況下都用指針類型;如果修改接受者中的值此疹,必須用指針類型;

使用指針類型的接受者場景

  • 需要修改接受者中的值
  • 接受者是拷貝代價比較大對象
  • 保持一致性,如果有某個方法使用了指針接受者蝗碎,那么其他的方法也應該使用指針接受者

注意:

  • 不能給系統(tǒng)類型添加方法
  • 不能給別的包定義的類型添加方法
package main

import "fmt"

type student struct {
    name string
    age int
    gender string
    hobby []string
}

//非指針類型接受者
func (s student) methodTest() {
    //非指針類型是不能改值
    s.age = 20
    fmt.Printf("學生的姓名是%s\n", s.name)
}

//指針類型接受者
func (s *student) methodTestUpdate() {
    s.age = 20
    fmt.Printf("學生的姓名是%s\n", s.name)
}

func main() {
    s := student{
        name: "aaa",
        age: 18,
    }
    s.methodTest()  //學生的姓名是aaa
    // 不能改值
    fmt.Printf("學生的年齡是%d\n", s.age)   //學生的年齡是18

    s2 := &student{
        name: "bbb",
        age: 18,
    }
    s2.methodTestUpdate()   //學生的姓名是bbb
    fmt.Printf("學生的年齡是%d\n", s2.age)  //學生的年齡是20
}

匿名字段

沒有變量名湖笨,只有類型的字段
不推薦匿名字段的寫法

package main

import "fmt"

//匿名字段,每個類型只能用一次蹦骑,不建議寫
type student struct {
    name string
    string
    int
}

func main() {

    s := student{
        name: "aaa",
        string: "222",
    }
    fmt.Println(s.name)
    fmt.Println(s.string) 
    fmt.Println(s.int) 

}

結構體嵌套

package main

import "fmt"

type address struct {
    province string
    city string
}

type student struct {
    name string
    age int
    addr address
}

func main() {

    s := student{
        name: "aaa",
        age: 20,
        addr : address{
            province: "山東",
            city: "煙臺",
        },
    }
    fmt.Println(s)               //{aaa 20 {山東 煙臺}}
    fmt.Println(s.name)          //aaa
    fmt.Println(s.addr.province) //山東
    fmt.Println(s.addr.city)     //煙臺
}

嵌套匿名結構體

匿名字段支持簡寫慈省,可以不加類型名
匿名字段沖突時,需要加上類型名眠菇,不能省略

package main

import "fmt"

type address struct {
    province string
    city string
}

type email struct {
    province string
    test string
}

type other struct {
    province string
    tmp string
}

type student struct {
    name string
    age int
    addr address
    //匿名字段
    email
    other
}

func main() {

    s := student{
        name: "aaa",
        age: 20,
        addr : address{
            province: "山東",
            city: "煙臺",
        },
        email: email{
            province: "1",
            test: "2",
        },
        other: other{
            province: "3",
            tmp: "4",
        },
    }
    fmt.Println(s)               //{aaa 20 {山東 煙臺} {1 2} {3 4}}
    fmt.Println(s.name)          //aaa
    fmt.Println(s.addr.province) //山東
    fmt.Println(s.addr.city)     //煙臺

    //可省略類型名
    fmt.Println(s.test)          //2
    //匿名字段沖突時边败,需要加上類型名,不能省略
    // fmt.Println(s.province)   //ambiguous selector s.province
    fmt.Println(s.email.province) //1
    
}

結構體的“繼承”

利用結構體嵌套捎废、匿名字段笑窜,實現(xiàn)結構體的“繼承”

package main

import "fmt"


type person struct {
    name string
}

func (p *person)dinner() {
    fmt.Printf("%s 要吃飯!\n", p.name)
}

type student struct {
    number int
    *person
}

func (s *student)study() {
    fmt.Printf("%s的學號是%d\n", s.name, s.number)
}

func main() {

    stu := student {
        number: 100,
        person: &person{
            name: "張三",
        },
    }
    fmt.Println(stu.name)
    fmt.Println(stu.number)
    stu.study()
    stu.dinner()
}

結構體與JSON序列化

序列化:把編程語言里面的數(shù)據(jù)轉換成JSON格式的字符串
反序列化:把JONS格式的字符串轉成編程語言中的對象

package main

import (
    "fmt"
    "encoding/json"
)

type Student struct {
    Id int `json:"id"` //通過tag實現(xiàn)json序列化該字段時的key
    Name string `json:"name"`
}


func main() {

    stu1 := &Student{
        Id: 1,
        Name: "張三",
    }

    fmt.Println("序列化:把編程語言里面的數(shù)據(jù)轉換成JSON格式的字符串")
    v, err := json.Marshal(stu1)
    if err != nil {
        fmt.Println("JSON格式化出錯登疗!")
        fmt.Println(err)
        return
    }
    fmt.Println(v)                 //[]byte
    fmt.Println(string(v))         //把[]byte轉換成string
    fmt.Printf("%#v\n", string(v)) //看真實的格式

    fmt.Println("反序列化:把JONS格式的字符串轉成編程語言中的對象") 
    str := string(v)
    // str := "{\"Id\":1,\"Name\":\"張三\"}"
    var stu2 = &Student{}
    json.Unmarshal([]byte(str), stu2)
    fmt.Println(*stu2) 
    fmt.Printf("%T\n", stu2)  
}

輸出結果是:
序列化:把編程語言里面的數(shù)據(jù)轉換成JSON格式的字符串
[123 34 105 100 34 58 49 44 34 110 97 109 101 34 58 34 229 188 160 228 184 137 34 125]
{"id":1,"name":"張三"}
"{\"id\":1,\"name\":\"張三\"}"
反序列化:把JONS格式的字符串轉成編程語言中的對象
{1 張三}
*main.Student

結構體tag

tag是結構體的元信息排截,可以在運行的時候通過反射的機制讀取出來。例如定義json序列化時的tag辐益。

type Student struct {
    Id int `json:"id"` //通過tag實現(xiàn)json序列化該字段時的key
    Name string `json:"name"`
}

小練習

小練習1:結構體+函數(shù)

package main

import (
    "fmt"
    "os"
)

//使用函數(shù)實現(xiàn)一個簡單的圖書管理系統(tǒng)
//每本書都有書名断傲、作者、價格智政、上架信息
//用戶可以在控制臺添加書籍认罩、修改書籍信息、打印所有的書籍列表续捂、退出操作

type book struct {
    title string
    author string
    price float32
    publish bool
}

//定義一個book指針的切片

// var bookList = make([]book, 0, 200)
var bookList = make([]*book, 0, 200)


// 獲取用戶輸入
func userInput() (title string, author string, price float32, publish bool){
    fmt.Print("請輸入標題:")
    fmt.Scanln(&title)
    fmt.Print("請輸入作者:")
    fmt.Scanln(&author)
    fmt.Print("請輸入價格:")
    fmt.Scanln(&price)
    fmt.Print("請輸入出版信息[true|false]:")
    fmt.Scanln(&publish)
    return
}

// 添加書籍
func addBook(){
    var (
        title string
        author string
        price float32
        publish bool
    )
    title, author, price, publish = userInput()

    newBook := book{title, author, price, publish}
    // bookList = append(bookList, newBook)
    bookList = append(bookList, &newBook)
    fmt.Println("添加書籍成功猜年!")
}

//修改書籍
func updateBook(){
    var (
        updateTitle string
        existsFlag bool
        title string
        author string
        price float32
        publish bool
    )

    fmt.Print("請輸入要修改的原書籍名稱:")
    fmt.Scanln(&updateTitle)

    existsFlag = false
    for _, bookInto := range bookList{
        if bookInto.title == updateTitle {
            existsFlag = true
        }
    }
    if !existsFlag {
        fmt.Println("書籍不存在!")
        return
    }


    title, author, price, publish = userInput()


    // newBook := book{title, author, price, publish}
    // for index, bookInto := range bookList{
    //  if bookInto.title == updateTitle {
    //      bookList[index] = newBook
    //      fmt.Println("書籍修改成功疾忍!")
    //  }
    // }

    for _, bookInto := range bookList{
        if bookInto.title == updateTitle {
            p := bookInto
            p.title = title
            p.author = author
            p.price = price
            p.publish = publish
            fmt.Println("書籍修改成功乔外!")
        }
    }
    
}


//展示書籍列表
func displayBook(){
    if len(bookList) == 0 {
        fmt.Println("無書籍!")
        return 
    }
    for index, bookInto := range bookList{
        fmt.Printf("序號:%v\n", index+1)
        fmt.Printf("標題:%s\n", bookInto.title)
        fmt.Printf("作者:%s\n", bookInto.author)
        fmt.Printf("價格:%0.2f\n", bookInto.price)
        fmt.Printf("標題:%t\n", bookInto.publish)
    }
}

func showMenu(){
    fmt.Println("1. 添加書籍")
    fmt.Println("2. 修改書籍信息")
    fmt.Println("3. 展示所有書籍")
    fmt.Println("4. 退出")
}

func main() {

    for {
        showMenu()
        fmt.Print("請輸入操作序號:")
        var opt string
        fmt.Scanln(&opt)
        switch opt {
        case "1":
            fmt.Println("--添加書籍操作--")
            addBook()
            fmt.Println("---------------")  
        case "2":
            fmt.Println("--修改書籍操作--")
            updateBook()
            fmt.Println("---------------")  
        case "3":
            fmt.Println("--展示書籍操作--")
            displayBook()
            fmt.Println("---------------")  
        case "4":
            fmt.Println("--離開操作--")
            os.Exit(0)
        default :
            fmt.Println("錯誤的操作選項一罩!")
            fmt.Println("---------------")  
        }
    }
    
} 

小練習2:結構體+方法

package main

import (
    "fmt"
    "os"
)
//使用方法實現(xiàn)一個簡單的學生管理系統(tǒng)
//每本書都有學號杨幼、姓名、年齡聂渊、班級
//用戶可以在控制臺添加學生差购、修改學生、刪除學生汉嗽、展示學生列表欲逃、退出操作

type Student struct {
    id int
    name string
    age int
    class string
}

//構造函數(shù)
func NewStudent(id int, name string, age int, class string) *Student {
    return &Student{
        id: id,
        name: name,
        age: age,
        class: class,
    }
}

type StuMng struct {
    stulist []*Student
}

func NewStuMng() *StuMng {
    return &StuMng{
        stulist: make([]*Student, 0, 100),
    }
}

//添加學生
func (s *StuMng)addStudent(stu *Student) {
    s.stulist = append(s.stulist, stu)
    fmt.Println("添加學生成功!")

}

//判斷學號是否存在
func (s *StuMng)stuIdIsExists(id int) bool {
    existsFlag := false
    for _, value := range s.stulist {
        if value.id == id {
            existsFlag = true
        }
    }
    return existsFlag
}

//修改學生
func (s *StuMng)updateStudent(stu *Student) {
    if !s.stuIdIsExists(stu.id) {
        fmt.Println("該學生學號不存在饼暑!")
        return
    }
    for index, value := range s.stulist {
        if value.id == stu.id {
            s.stulist[index] = stu
        }
    }
    fmt.Println("修改學生成功稳析!")

}

//刪除學生
func (s *StuMng)deleteStudent(id int) {
    if !s.stuIdIsExists(id) {
        fmt.Println("該學生學號不存在洗做!")
        return
    }
    for index, value := range s.stulist {
        if value.id == id {
            s.stulist = append(s.stulist[:index], s.stulist[index+1:]...)
        }
    }
    fmt.Println("刪除學生成功!")

}

//展示所有學生
func (s *StuMng)displayStudentList() {
    if len(s.stulist) == 0 {
        fmt.Println("無")
        return
    }
    for _, stu := range s.stulist {
        fmt.Printf("學號:%d彰居,姓名:%s诚纸,年齡:%d,班級:%s \n", stu.id, stu.name, stu.age, stu.class)
    }
}

//操作菜單
func showMenuOpt(){
    fmt.Println("1. 添加學生")
    fmt.Println("2. 修改學生")
    fmt.Println("3. 刪除學生")
    fmt.Println("4. 展示所有學生")
    fmt.Println("5. 退出")
}

// 獲取用戶輸入
func userInputContent() *Student{
    var (
        id int
        name string
        age int
        class string
    )
    fmt.Print("請輸入學號:")
    fmt.Scanln(&id)
    fmt.Print("請輸入姓名:")
    fmt.Scanln(&name)
    fmt.Print("請輸入年齡:")
    fmt.Scanln(&age)
    fmt.Print("請輸入班級:")
    fmt.Scanln(&class)
    return NewStudent(id, name, age, class)
}

func main() {

    sg := NewStuMng()
    
    for {
        showMenuOpt()
        fmt.Print("請輸入操作序號:")
        var opt string
        fmt.Scanln(&opt)
        switch opt {
        case "1":
            fmt.Println("--添加學生操作--")
            stu := userInputContent()
            sg.addStudent(stu)
            fmt.Println("---------------")  
        case "2":
            fmt.Println("--修改學生操作--")
            stu := userInputContent()
            sg.updateStudent(stu)
            fmt.Println("---------------")  
        case "3":
            fmt.Println("--刪除學生操作--")
            var id int
            fmt.Print("請輸入學號:")
            fmt.Scanln(&id)
            sg.deleteStudent(id)
            fmt.Println("---------------")  
        case "4":
            fmt.Println("--查詢所有學生操作--")
            sg.displayStudentList()
            fmt.Println("---------------")  
        case "5":
            fmt.Println("--離開操作--")
            os.Exit(0)
        default :
            fmt.Println("錯誤的操作選項陈惰!")
            fmt.Println("---------------")  
        }
    }
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末畦徘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子抬闯,更是在濱河造成了極大的恐慌井辆,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溶握,死亡現(xiàn)場離奇詭異杯缺,居然都是意外死亡,警方通過查閱死者的電腦和手機奈虾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門夺谁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肉微,你說我怎么就攤上這事匾鸥。” “怎么了碉纳?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵勿负,是天一觀的道長。 經(jīng)常有香客問我劳曹,道長奴愉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任铁孵,我火速辦了婚禮锭硼,結果婚禮上,老公的妹妹穿的比我還像新娘蜕劝。我一直安慰自己檀头,他們只是感情好,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布岖沛。 她就那樣靜靜地躺著暑始,像睡著了一般。 火紅的嫁衣襯著肌膚如雪婴削。 梳的紋絲不亂的頭發(fā)上廊镜,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音唉俗,去河邊找鬼嗤朴。 笑死配椭,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的播赁。 我是一名探鬼主播颂郎,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼吼渡,長吁一口氣:“原來是場噩夢啊……” “哼容为!你這毒婦竟也來了?” 一聲冷哼從身側響起寺酪,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坎背,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后寄雀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體得滤,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年盒犹,在試婚紗的時候發(fā)現(xiàn)自己被綠了懂更。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡急膀,死狀恐怖沮协,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卓嫂,我是刑警寧澤慷暂,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站晨雳,受9級特大地震影響行瑞,放射性物質發(fā)生泄漏。R本人自食惡果不足惜餐禁,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一血久、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帮非,春花似錦氧吐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至庄岖,卻和暖如春豁翎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背隅忿。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工心剥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留邦尊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓优烧,卻偏偏與公主長得像蝉揍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子畦娄,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容

  • golang中是沒有class的,但是有一個結構體struct,有點類似,他沒有像java,c++中繼承的概念,但...
    Link_Biao閱讀 1,321評論 0 1
  • Go語言中的基礎數(shù)據(jù)類型可以表示一些事物的基本屬性又沾,但是當我們想表達一個事物的全部或部分屬性時,這時候再用單一的基...
    Every_dawn閱讀 352評論 0 2
  • 一熙卡、結構 1杖刷、結構體類似于Java中 無方法的類。 2驳癌、結構體是值類型滑燃,值類型,值類型M窍省表窘!重要的事情強調(diào)好幾遍!甜滨!...
    R_X閱讀 303評論 0 0
  • ?一個結構體類型可以包含若干個字段乐严,也可以不包含任何字段⊙薹停空結構體可以關聯(lián)上一些方法麦备,從而看成是函數(shù)的特殊版本。 ...
    one_zheng閱讀 879評論 0 1
  • Output: 注意事項昭娩,在標簽中json:"nickname" 外層符號為鍵盤Tab健上方的鍵凛篙。json冒號和后...
    第八共同體閱讀 6,996評論 1 1