1. 程式人生 > 其它 >Golang第五章:結構體和物件

Golang第五章:結構體和物件

Golang面向物件

  1. Golang沒有類,Go的結構體相對於其它程式語言的類

  2. Golang去掉了傳統OOP語言的繼承、方法過載、建構函式和解構函式、隱藏的指標等等

  3. Golang仍有面向物件程式設計的繼承、封裝和多型的特性,只是實現方式不同

建立結構體例項的四種方法

type Cat struct {
    Name string
    Age int
    Color string
}

func main() {
    // 結構體例項建立方式1
    var cat1 Cat
    cat1.Name = "小白"

    // 方式2
    cat2 := Cat{"
haha", 13, ""} fmt.Println(cat2) fmt.Println(cat1) // 方式3 var cat3 *Cat = new(Cat) (*cat3).Name = "小花" // 以上也可以寫成cat3.Name = "小花" // 原因:go的設計者為了程式設計師使用方便,底層會對以上語句進行處理,會轉化成(*cat3) // 方式4 // 下面的語句,也可以直接給欄位賦值 // var cat4 *Cat = &Cat{"haha", 321, "綠"} var cat4 *Cat = &Cat{} (
*cat4).Name = "小曹" // 以上也可以寫成cat3.Name = "小花" // 原因:go的設計者為了程式設計師使用方便,底層會對以上語句進行處理,會轉化成(*cat3) fmt.Println(*cat4) fmt.Println(*cat3) fmt.Println(cat2) fmt.Println(cat1) }

結構體的注意事項

  1. 結構體的所有欄位在記憶體中是連續的

  2. 對一個結構體進行type重新定義,Golang認為是新的資料型別,但相互間可以強轉

  3. 結構體的每個欄位上,可以寫上一個tag,該tag可以通過反射機制獲取,常見的使用場景就是序列化和反序列化

  4. 如果一個變數實現了String()方法,那麼fmt.Println預設會呼叫這個變數的String()進行輸出——該功能與java的toString()一致

  5. 不管呼叫形式如何,真正決定是值拷貝還是地址拷貝,看這個方法是和哪個型別繫結——如func (cat *Cat)為地址拷貝,func (cat Cat)為值拷貝

結構體序列化

import (
    "fmt"
    "encoding/json"
)

type Cat struct {
    Name string `json: "name"`
    Age int    `json:"age"`
    Color string    `json:"skill"`
}

func main() {
    // 方式2
    cat2 := Cat{"haha", 13, ""}
    jsonStr, err := json.Marshal(cat2)
    if err != nil {
        fmt.Println("json 處理錯誤", err)
    }
    fmt.Println("jsonStr", string(jsonStr))
}

結構體繫結方法

建立結構體例項指定欄位值

工廠模式

package main

import (
    "fmt"
    "go_code/project05/factory/model"
)

func main() {
    var str = model.NewStudent("tom~", 89.2)
    fmt.Println(str)
    fmt.Println("score:", str.GetScore())
}


package model

//定義一個結構體
type student struct {
    Name string
    score float64
}

func NewStudent(n string, s float64) *student {
    return &student {
        Name: n,
        score: s,
    }
}

func (s *student)GetScore() (float64) {
    return s.score
}

繼承

結構體可以使用巢狀結構體所有的方法和欄位,無論首字母大小寫

package main

import (
    "fmt"
)

// 學生
type Student struct {
    Name string
    Age int
    Score int
}

func (stu *Student) showInfo() {
    fmt.Printf("學生名=%v 年齡=%v 成績=%v\n", stu.Name, stu.Age, stu.Score)
}

func (stu *Student) SetScore(score int) {
    stu.Score = score
}

// 小學生
type Pupil struct {
    Student
}

func (p *Pupil) Testing() {
    fmt.Println("小學生在考試")
}

func main() {
    pupil := &Pupil{}
    pupil.Student.Name = "tom~"
    pupil.Student.Age = 8
    pupil.Testing()
    pupil.SetScore(25)
    pupil.showInfo()
}

介面

// 宣告一個介面
type Usb interface {
    Start()
    Stop()
}

type Phone struct {

}

func (p Phone) Start() {
    fmt.Println("phone start")
}

func (p Phone) Stop() {
    fmt.Println("phone bomb")
}

type Computer struct {

}

func (c Computer) Working(usb Usb) {
    usb.Start()
    usb.Stop()
}

func main() {
    computer := Computer{}
    phone := Phone{}
    
    computer.Working(phone) // 輸出phone start、phone bomb
}

 一個自定義型別(不止是結構體)只有實現了某個介面,才能將自定義型別的例項(變數)賦給介面型別

// 宣告一個介面
type Usb interface {
    Start()
}

type Phone struct {

}

type integer int

func (i integer) Start() {
    fmt.Println("integer Start")
}
func (p Phone) Start() {
    fmt.Println("phone start")
}

func main() {
    var phone Phone
    var usb Usb = phone
    usb.Start()

    var i integer
    var usb2 Usb = i
    usb2.Start()
}

型別斷言

 

型別斷言(Type Assertion)是一個使用在介面值上的操作,用於檢查介面型別變數所持有的值是否實現了期望的介面或者具體的型別。

type Point struct {
    x int
    y int
}

func main() {
    var a interface{}
    var point Point = Point{1, 2}
    a = point
    var b Point
    b, ok := a.(Point)
    if ok {
        fmt.Println("convert success")
    } else {
        fmt.Println("convert failed")
    }

    fmt.Println(b)
}