Structs and Interfaces

Structs(結構)

結構是一種使用者自定的型態,它可將不同的資料型態串在一起。

結構宣告

type rect struct {
    left int32
    top int32
    right int32
    bottom int32
}

var x rect
fmt.Println(x) // {0 0 0 0}
fmt.Println(reflect.TypeOf(x)) // main.rect

結構初始化

var a rect
a.left = 1
a.top = 2
a.right = 3
a.bottom = 4
fmt.Println(a) // {1 2 3 4}

//按照顺序提供初始化值
var b rect = rect {
1,
2,
3,
45,
}
fmt.Println(b) // {1 2 3 45}

//too few values in struct initializer
//var c rect = rect {
//1,
//2,
//}

//透過 field:value 的方式初始化 好處是可以任意順序
var d rect = rect {
left:1,
top:2,
right:3,
bottom:4,
}
fmt.Println(d) // {1 2 3 4}

var e rect = rect {
top:2,
left:1,
}
fmt.Println(e) // {1 2 0 0}

結構指標

var g1 rect = rect {1, 2, 3, 4,}
fmt.Println(g1) // {1 2 3 4}

var pointG *rect = &g1;
fmt.Println(pointG, reflect.TypeOf(pointG)) // &{1 2 3 4} *main.rect
pointG.left = 100
fmt.Println(pointG, g1) // &{100 2 3 4} {100 2 3 4}

匿名属性

// 一個struct類型的匿名屬性的方法可以通過該struct對象直接調用。
// 這個特性可以讓我們實現類似於傳統OOP中的繼承特性。

type Human struct {
    name string
    age int
}
type Woman struct {
    Human
    weight int
}
type Man struct {
    name string
    weight int
}
type Student struct {
    Human
    Man
    age int
}

mark := Human {"5",9,}
fmt.Println("mark : ", mark) // mark :  {5 9}

mary := Woman {Human{"5",1},9,}
fmt.Println("mary : ", mary) // mary :  {{5 1} 9}

mary.Human = Human{"5",1}
mary.weight = 9

john := Student {
Human{"中", 1,},
Man{"華", 2,},
3,
}
fmt.Println("john : ", john) // john :  {{中 1} {華 2} 3}

fmt.Println("john : ", john.weight) // 2
//fmt.Println("john : ", john.name) // ambiguous selector john.name
fmt.Println("john : ", john.Human.name) // 中
fmt.Println("john : ", john.Man.name) // 華
fmt.Println("john : ", john.age) // 3
fmt.Println("john : ", john.Human.age) // 1

method 定義屬於結構的方法

// 定義結構
type User struct {
    name string
}

//定義屬於結構User的方法
func (user *User) SetName (newName string) {
    user.name = newName
}
func (user *User) GetName() string {
    return user.name
}

var user User
fmt.Println("user is: ", user) // user is:  {}
user.SetName("new")
fmt.Println("user is: ", user) // user is:  {new}
fmt.Println("user.name is: ", user.GetName()) // user.name is:  new

method 繼承與覆寫

// 定義結構
type PowerUser struct {
    User
    age int
}

//定義屬於結構PowerUser的方法
func (user *PowerUser) SetName(newName string) {
    user.name = newName + ":PowerUser"
}

var user PowerUser
fmt.Println("user is: ", user) // user is:  {{} 0}
user.SetName("new")
fmt.Println("user.name is: ", user.GetName()) // user.name is:  new:PowerUser
user.User.SetName("new")
fmt.Println("user.name is: ", user.GetName()) // user.name is:  new:User

Interface(接口)

Interface定義了一個或一組method(s),這些method(s)只有函數簽名, 沒有具體的實現代碼。
若某個數據類型實現了Interface中定義的那些被稱為"methods"的函數,
則稱這些數據類型實現(implement)了interface。

// 我們再複習一下 結構 和 結構指標
type Cat struct {
    name string
}

func (self *Cat) GetName() string {
    return self.name
}
func (self *Cat) Run() bool {
    return true
}

type Dog struct {
    name string
}

func (self *Dog) GetName() string {
    return self.name
}
func (self *Dog) Run() bool {
    return true
}
func (self *Dog) Jump() bool {
    return true
}

func test() {
    var myCat Cat = Cat{name: "SuperCat"}
    var myCatPoint *Cat = &myCat

    var myDog Dog = Dog{"SuperDog"}
    var myDogPoint *Dog = &myDog

    fmt.Println(myCatPoint.GetName()) // SuperCat
    fmt.Println(myDogPoint.GetName()) // SuperDog

    // myCatPoint = &myDog // cannot use &myDog (type *Dog) as type *Cat in assignment
}
// 定義接口類型 Human
type IAnimal interface {
    GetName() string
    Run() bool
}

func test2() {
    var myCat Cat = Cat{name: "SuperCat"}
    var myDog Dog = Dog{"SuperDog"}

    // 接口的宣告要一致(回傳型別 函式名稱 參數數量與型別)
    var myAnimal IAnimal
    myAnimal = &myCat
    fmt.Println(myAnimal.GetName()) // SuperCat
    myAnimal = &myDog
    fmt.Println(myAnimal.GetName()) // SuperDog
    fmt.Println(myAnimal.Run()) // true
    // fmt.Println(myAnimal.Jump()) 
    // myAnimal.Jump undefined (type IAnimal has no field or method Jump)
}

// 定義接口類型 Human
type IHuman interface {
    GetName() string
    GetAge() int 
}

// 定義接口類型 Man
type IMan interface {
    IHuman // Man 接口中嵌入了 Human 接口 , Man 會獲取 Human 所有方法
    GetWeight() int    
    // GetAge() int // duplicate method GetAge
}
// 定義結構 Student 
type Student struct {
    name string
    age int
    weight int
}

// 定義結構 Student 的方法
func (self* Student) GetName() string {
    return self.name
}
func (self* Student) GetAge() int {
    return self.age
}
func (self* Student) GetWeight() int {
    return self.weight
}
// Student 實現了 Human 和 Man 兩個接口
mark := Student {
    name : "mark_student",
    age : 20,
    weight : 65,
}

var i_human IHuman
i_human = &mark
fmt.Println(i_human, reflect.TypeOf(i_human)) // &{mark_student 20 65} *main.Student
fmt.Println(i_human.GetName())                // mark_student

var i_man IMan
i_man = &mark
fmt.Println(i_man, reflect.TypeOf(i_man)) // &{mark_student 20 65} *main.Student
fmt.Println(i_man.GetName())              // mark_student
fmt.Println(i_man.GetAge())               // 20
fmt.Println(i_man.GetWeight())            // 65