1、匿名组合(继承思想)

(1)当匿名字段也是一个结构体的时候,这个结构体包含的字段全部被隐式的引入当前定义的结构体中
(2)当匿名字段是非结构体时,可以用 变量.类型名 操作此变量
(3)同名字段,如果能在本作用域找到此成员,就操作此成员;如果没找到,就操作继承的成员。

package main

import (
    "fmt"
)

type Person struct {
    name string
    age  int
}

type Student struct {
    Person
    id int
    int
}

func main() {
    // 1、初始化
    var s1 = Student{Person{"LiMing", 18}, 1, 2}
    fmt.Println("s1 = ", s1)

    // 2、指定成员初始化
    s2 := Student{Person: Person{name: "LiMing"}}
    fmt.Println("s2 = ", s2)

    // 3、使用匿名字段
    fmt.Println("结构体匿名字段:", s1.Person)
    fmt.Println("结构体匿名字段2:", s1.name)
    fmt.Println("非结构体匿名字段:", s1.int)
}

2、方法(封装思想)

2.1、通过 func (参数名 类型名称) 方法名(){},给某个类型绑定一个方法,func后边的参数也会传入方法中

package main

import (
    "fmt"
)

// 1、面向过程
func Add1(a, b int) int {
    return a + b
}

// 2.1、面向对象,定义一个结构体MyMath
// 2.2、给MyMath绑定一个方法Add2
type MyMath struct{}

func (this MyMath) Add2(a, b int) int {
    return a + b
}

func main() {
    fmt.Println("Add1 = ", Add1(1, 2))

    myMath := MyMath{}
    fmt.Println("myMath.Add2() = ", myMath.Add2(1, 2))
}

2.2、值语义,引用语义

(1)值语义:里边的值相当于外部的拷贝,对它修改不会影响外部的值
(2)引用语义:引用传递
(3)真正使用时,调用不受方法集约束,编译器总是查找全部方法,并自动转换

package main

import (
    "fmt"
)

type Person struct {
    name string
    age  int
}

// 值语义,里边的this相当于外部的拷贝,对他修改不会影响外部的值
func (this Person) setInfo01(name string, age int) {
    this.name = name
    this.age = age
}

// 引用语义,引用传递
func (this *Person) setInfo02(name string, age int) {
    this.name = name
    this.age = age
}

func main() {
    person := Person{"LiMing", 1}
    fmt.Println("person = ", person)

    person.setInfo01("LiMing", 18)
    fmt.Println("值语义 person = ", person)

    (&person).setInfo02("Liming", 18)
    fmt.Println("引用语义 person = ", person)

    // 编译器内部自动做转换
    person.setInfo02("LiMing", 20)
    fmt.Println("引用语义2 person = ", person)
}

2.3、方法的继承

package main

import (
    "fmt"
)

type Person struct {
    name string
    age  int
}

func (this *Person) PrintInfo() {
    fmt.Println("person = ", this)
}

type Student struct {
    Person
    id int
}

func main() {
    student := Student{Person{"LiMing", 18}, 1}
    student.PrintInfo()
}

// 打印内容
person =  &{LiMing 18}

2.4、方法的重写/同名方法

就近原则

package main

import (
    "fmt"
)

type Person struct {
    name string
    age  int
}

func (this *Person) PrintInfo() {
    fmt.Println("person = ", this)
}

type Student struct {
    Person
    id int
}

func (this *Student) PrintInfo() {
    fmt.Println("student = ", this)
}

func main() {
    student := Student{Person{"LiMing", 18}, 1}
    student.PrintInfo()
}

// 打印内容
student =  &{{LiMing 18} 1}

2.5、方法值、方法表达式

(1)方法值省略了调用者
(2)方法表达式需要把调用者写到()中

package main

import (
    "fmt"
)

type Person struct {
    name string
    age  int
}

func (this *Person) PrintInfo() {
    fmt.Println("person = ", this)
}

func main() {
    person := Person{"LiMing", 18}

    // 方法值
    fun1 := person.PrintInfo
    fun1()

    // 方法表达式
    fun2 := (*Person).PrintInfo
    fun2(&person)
}

3、接口(多态思想)

(1)通过 type 名称 interface 定义接口,接口通常以er结尾
(2)接口中的方法只有声明,没有实现
(3)接口可以继承

package main

import (
    "fmt"
)

type Personer interface {
    hello()
}

type Chinese struct {
    addr string
}

func (p *Chinese) hello() {
    fmt.Println("你好")
}

type American struct {
    addr string
}

func (p *American) hello() {
    fmt.Println("hello")
}

func sayHello(p Personer) {
    p.hello()
}

func main() {
    sayHello(&Chinese{})
    sayHello(&American{})
}

3.1、空接口不包含任何方法,即所有类型都实现了它,万能类型

package main

import (
    "fmt"
)

type Person struct {
    name string
    age  int
}

func main() {
    // 空接口没有方法,即所有类型都实现了它
    s := make([]interface{}, 3)
    s[0] = 1
    s[1] = "hello"
    s[2] = Person{}

    // 类型查询
    for index, value := range s {
        if data, ok := value.(int); ok {
            fmt.Printf("我是int类型 index = %d,data = %d\n", index, data)
        } else if data, ok := value.(string); ok {
            fmt.Printf("我是string类型 index = %d,data = %s\n", index, data)
        } else if data, ok := value.(Person); ok {
            fmt.Printf("我是Person类型 index = %d,data = %v\n", index, data)
        }
    }

    fmt.Println("------------------------------")

    // 类型查询
    for index, value := range s {
        switch value.(type) {
        case int:
            fmt.Printf("我是int类型 index = %d,data = %d\n", index, value)
        case string:
            fmt.Printf("我是string类型 index = %d,data = %s\n", index, value)
        case Person:
            fmt.Printf("我是Person类型 index = %d,data = %v\n", index, value)
        }
    }
}