package main

import (
    "fmt"
)

//父对象
type Human struct {
    name  string
    age   int
    phone string
}

//子对象,因为有了匿名字段,所以就继承了父对象Human的所有字段,还有父对象已经实现了的方法
type Student struct {
    Human  //匿名字段,共有的匿名字段Human,称作字段的继承
    school string
    loan   float32 //借款
}

//子对象,因为有了匿名字段,所以就继承了父对象Human的所有字段,还有父对象已经实现了的方法
type Employee struct {
    Human   //匿名字段,共有的匿名字段Human,称作字段的继承
    company string
    money   float32 //花钱
}

//在多个对象共有的匿名字段Human上面定义了一个方法,这个方法就是一个继承方法
func (h *Human) SayHi() (hi string) {
    hi = h.name + " Said: Hi, I am " + h.name + " you can call me on " + h.phone
    return hi
}

//Employee的method重写继承Human的method
func (e *Employee) SayHi() (hi string) {
    hi = e.name + " Said: Hi, I am " + e.name + " I work at " + e.company + ". Call me on " + e.phone
    return hi
}

//给两个子对象Student和Employee添加一个继承方法,只需要在父对象Human上实现该方法即可
func (h *Human) Sing(song string) (out string) {
    out = h.name + " is singing the song - " + song //谁在唱歌
    return out
}

//给两个子对象Student和Employee添加一个继承方法,只需要在父对象Human上实现该方法即可
func (h *Human) Guzzle(beer string) (out string) {
    out = h.name + " is guzzling his/her beer - " + beer //谁在狂饮啤酒
    return out
}

//Student实现BorrowMoney方法
func (s *Student) BorrowMoney(amount float32) (out float32) {
    s.loan += amount //累加借款的金额
    out = s.loan
    return out
}

//Employee实现SpendSalary方法
func (e *Employee) SpendSalary(amount float32) (out float32) {
    e.money -= amount //累减剩余的薪水
    out = e.money
    return out
}

//以下3个接口内部的方法,返回值参数的名称及其类型必须显式地声明

// 定义男子汉接口
type Men interface {
    SayHi() (hi string)
    Sing(song string) (out string)
    Guzzle(beer string) (out string)
}

//定义小伙子接口
type YoungChap interface {
    SayHi() (hi string)
    Sing(song string) (out string)
    BorrowMoney(amount float32) (out float32)
}

//定义老先生接口
type ElderlyGent interface {
    SayHi() (hi string)
    Sing(song string) (out string)
    SpendSalary(amount float32) (out float32)
}

//Go语言的继承范例和重写范例还有接口范例
func main() {
    mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}          //小伙子
    jack := Student{Human{"Jack", 21, "222-222-4579"}, "Tsinghua", 1500.00} //小伙子
    tom := Student{Human{"Tom", 29, "222-222-4548"}, "Peking", 3200.00}     //男子汉
    paul := Student{Human{"Paul", 26, "111-222-1314"}, "Harvard", 100}      //小伙子
    tim := Employee{Human{"Tim", 35, "222-222-9948"}, "Sina", 7500.00}      //男子汉
    kite := Employee{Human{"Kite", 36, "222-222-7848"}, "Sohu", 10500.00}   //男子汉
    sam := Employee{Human{"Sam", 58, "444-222-5520"}, "Golang Inc.", 8000}  //老先生
    hi1 := jack.SayHi()
    fmt.Println(hi1)
    hi2 := tim.SayHi()
    fmt.Println(hi2)
    fmt.Println("--------------------------------------")

    //定义小伙子YoungChap接口类型的变量inYoungChap
    var inYoungChap YoungChap
    //InYoungChap能存储Student
    //因为实现男子汉接口内部的方法时,这些方法的接收参数使用了指针,所以给接口赋值时必须使用对象的地址赋值
    inYoungChap = &jack
    fmt.Println("This is Jack, a Student:")
    hi3 := inYoungChap.SayHi()
    fmt.Println(hi3)
    out1 := inYoungChap.Sing("November rain")
    fmt.Println(out1)
    out2 := inYoungChap.BorrowMoney(1200.00)
    fmt.Println(out2)
    fmt.Println("--------------------------------------")

    //定义男子汉Men接口类型的变量inMen
    var inMen Men
    //Men能存储Employee
    //因为实现男子汉接口内部的方法时,这些方法的接收参数使用了指针,所以给接口赋值时必须使用对象的地址赋值
    inMen = &tim
    fmt.Println("This is Tim, an Employee:")
    hi4 := inMen.SayHi()
    fmt.Println(hi4)
    out3 := inMen.Sing("Born to be wild")
    fmt.Println(out3)
    out4 := inMen.Guzzle("Budweiser")
    fmt.Println(out4)
    fmt.Println("--------------------------------------")

    //定义男子汉ElderlyGent接口类型的变量inElderlyGent
    var inElderlyGent ElderlyGent
    //ElderlyGent能存储Employee
    //因为实现男子汉接口内部的方法时,这些方法的接收参数使用了指针,所以给接口赋值时必须使用对象的地址赋值
    inElderlyGent = &sam
    fmt.Println("This is Sam, an Employee:")
    hi5 := inElderlyGent.SayHi()
    fmt.Println(hi5)
    out5 := inElderlyGent.Sing("Born to be wild")
    fmt.Println(out5)
    out6 := inElderlyGent.SpendSalary(3800.00)
    fmt.Println(out6)
    fmt.Println("--------------------------------------")

    //定义Men切片
    fmt.Println("Let's use a slice of Men and see what happens")
    slMen := make([]Men, 3)
    //这三个对象有2种不同类型的元素(学生和职员)
    //所有元素都能存储到YoungChap、Men和ElderlyGent接口里,因为它们本质上都是interface的别名
    slMen[0], slMen[1], slMen[2] = &paul, &sam, &mike //注意:这样赋值超过3个会越界
    //使用 append 追加动态扩容切片的大小,让超过3个的对象也可以存储到接口的切片里
    slMen = append(slMen, &tom, &kite) //append方法会分配新的内存空间存储无法装进来的数据

    for _, v := range slMen {
        //因为定义的是Men切片,所以可以调用该切片接口内部的3个方法SayHi、Sing和Guzzle都不会出错
        fmt.Println(v.SayHi())
    }
    fmt.Println("--------------------------------------")
    fmt.Println("-----同1个对象调用2个接口里2个不同的方法,每个被调用的方法只属于其中的一个接口-----")
    var inYoungChapTom YoungChap
    var inMenTom Men
    inYoungChapTom = &tom
    inMenTom = &tom
    loan1 := inYoungChapTom.BorrowMoney(980.00)
    fmt.Println(loan1)
    guzzleBeer1 := inMenTom.Guzzle("Snow Beer")
    fmt.Println(guzzleBeer1)
    fmt.Println("--------------------------------------")

}



2017/06/15 20:30:36 server.go:73: Using API v1
2017/06/15 20:30:36 debugger.go:97: launching process with args: [/root/code/go/src/contoso.org/hello/debug]
API server listening at: 127.0.0.1:2345
2017/06/15 20:30:36 debugger.go:505: continuing
Jack Said: Hi, I am Jack you can call me on 222-222-4579
Tim Said: Hi, I am Tim I work at Sina. Call me on 222-222-9948
--------------------------------------
This is Jack, a Student:
Jack Said: Hi, I am Jack you can call me on 222-222-4579
Jack is singing the song - November rain
2700
--------------------------------------
This is Tim, an Employee:
Tim Said: Hi, I am Tim I work at Sina. Call me on 222-222-9948
Tim is singing the song - Born to be wild
Tim is guzzling his/her beer - Budweiser
--------------------------------------
This is Sam, an Employee:
Sam Said: Hi, I am Sam I work at Golang Inc.. Call me on 444-222-5520
Sam is singing the song - Born to be wild
4200
--------------------------------------
Let's use a slice of Men and see what happens
Paul Said: Hi, I am Paul you can call me on 111-222-1314
Sam Said: Hi, I am Sam I work at Golang Inc.. Call me on 444-222-5520
Mike Said: Hi, I am Mike you can call me on 222-222-XXX
Tom Said: Hi, I am Tom you can call me on 222-222-4548
Kite Said: Hi, I am Kite I work at Sohu. Call me on 222-222-7848
--------------------------------------
-----同1个对象调用2个接口里2个不同的方法,每个被调用的方法只属于其中的一个接口-----
4180
Tom is guzzling his/her beer - Snow Beer
--------------------------------------