Golang面向对象编程 匿名字段 方法 接口

面对过程强调过程,面向对象强调对象

包括三个内容
  • 匿名字段
  • 方法
  • 接口

匿名字段

可以理解为用类型别名来进行嵌套等操作,解释不太清楚,属于方便自己的操作

  • 可以分为3段内容
    • 普通匿名字段
    • 指针类型匿名字段
    • 多重继承匿名字段
      慕课网老师说不支持继承和多态(存疑)

定位就是使用类型别名 type 名字 struct{}

普通匿名字段

type Person struct { //夫类
    id int
    name string
    age int
}

type Student1 struct {        // 结构体嵌套  子类
    Person  //匿名字段 只有类型 没有名字
    score int
}

func main51() {
    var s1 Student1 = Student1{
        Person: Person{
            id:   1,
            name: "A",
            age:  18,
        },
        score:  98,
    }
    var s2 Student1 =Student1{Person{2,"B",18},98}
    //自动推导
    s3:=Student1{Person{3,"C",18},102}
    fmt.Println(s1,s2,s3)
    //指定初始化成员
    s4:=Student1{score: 99}
    fmt.Println(s4)
    s5:=Student1{Person{name: "小鸡"},80}
    fmt.Println(s5)
}

func main()  {
    var s1 Student1 =Student1{Person{2,"B",18},98}
    //成员操作      .操作符
    s1.score=87
    s1.id=110
    s1.Person.age=25
    s1.Person=Person{1,"V",12}

    fmt.Println(s1)


}

指针类型匿名字段

package main

import "fmt"

type Person2 struct { //夫类
    id int
    name string
    age int
}

type Student2 struct {        // 结构体嵌套  子类
    *Person2    //匿名字段 只有类型 没有名字
    score int
}

func main() {

    var s Student2
    s.score=90
    fmt.Println(s)  //打印出 { 90}
    //s.*Person2.id=1
    s.Person2=new(Person2)  //创建出一块新的地址来储存内容
    s.name="小A"
    s.id=11
    s.age=20
    fmt.Println(s)//打印出 {0xc0000a63c0 90}
    fmt.Println(s.name,s.age,s.id)//打印出 小A 20 11

    s.Person2=&Person2{
        id:   31,
        name: "e",
        age:  10,
    }
    fmt.Println(s.name,s.age,s.id)//打印出  e 10 31

}

多重继承匿名字段

package main

import "fmt"

type person04 struct {//父类
    name string
    sex string
    age int
}

type Person4 struct { //父类
    id int
    addr string

}

type Student4 struct {        // 结构体嵌套  子类
    //结构体成员为多个匿名字段
    Person4 //匿名字段 只有类型 没有名字
    person04
    score int
}

type human struct {
    Student4 //包含多个匿名字段
    country string
}

func main() {
    var s1 Student4
    s1=Student4{
        Person4:Person4{
            id:   1,
            addr: "北京路",
        },
        person04:person04{
            name: "du",
            sex:  "男",
            age:  21,
        },
        score:    100,
    }

    s2:=Student4{Person4{1,"贵州"},person04{"zhao","男",18},21}

    var s3 Student4
    s3.age=1
    s3.name="a"
    s3.id=1
    s3.score=1
    s3.sex="男"
    s3.addr="无语"

    //3个嵌套 爷父孙嵌套
    s4:=human{Student4{Person4{1,"北京路"},person04{"龙","男",19},100},"china"}

    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
    fmt.Println(s4)

}

慕课老师补充要点

自定义工厂函数,注意返回局部变量的地址!

package main

import "fmt"

type treenode struct {
    value int
    left,right *treenode
}
//工程函数

func createNode(value int)*treenode  {
    return &treenode{value: value}

}

func main() {
    //var a treenode
    //fmt.Println(a) {0  }
    a:=treenode{value: 3}
    a.left=&treenode{}      //&{0  0xc0000040a8}
    a.right=&treenode{5,nil,nil}        //&{5  }
    a.left.right = new(treenode)        //&{0  }
    a.right.left = createNode(2)    //&{2  }


    //nodes:=[]treenode{
    //  {value: 3},
    //  {},
    //  {6,nil,&a},
    //}
    //fmt.Println(nodes)

}

方法

除了名字和年龄,猫和狗的行为不同,行为可以用方法描述
方法和函数差不多,但方法不是函数
函数名和方法名重名没有影响
方法的定义

func (对象)方法名(函数参数列表)返回值    {
代码体
}

函数的定义

func 函数名(函数参数列表)返回值    {
代码体
}

具体代码

package main

import "fmt"

type cat struct { //除了名字和年龄,猫和狗的行为不同,行为可以用方法描述
    name string
    age int
}
type dog struct {
    name string
    age int
}
//方法的定义
//func (对象)方法名(函数参数列表)返回值    {
//代码体
//}

//函数的定义
//func 函数名(函数参数列表)返回值    {
//代码体
//}

func cats()  {
    fmt.Println("喵喵叫")
}

//方法: 需要绑定对象
//    结构体类型  可以成为对象类型
//    结构体作为接受者
//所有cat都能用
func (c cat)show()  {
    //fmt.Println("喵喵叫")
    fmt.Printf("我是%s,喵喵\n",c.name)
}

func (d dog)show()  {
    //fmt.Println("汪汪叫")
    fmt.Printf("我是%s,汪汪\n",d.name)
}
//函数名和方法名重名没有影响
//方法与方法名重名也没有影响,因为对象不同

func main() {
    //对象创建

    c:=cat{"旺财",2}
    var c1 cat
    //c1=cat{"小狗",2}
    //fmt.Println(c1)

    fmt.Println(c)
    //对象.方法              包.函数               结构体.成员
    c.show()
    c1.show()
    //cats() //函数调用


    var d dog
    d=dog{"旺财二号",2}
    fmt.Println(d)
    d.show()


}

方法的指针运用

/对象的不同  方法名相同 不冲突
//方法调用中 方法的接受者从普通的对象类型变成指针类型对象
//普通类型和指针类型表示的是相同对象的类型
//值传递(s student7) 地址传递(s *student7)

func (s *student7)Print()  {
    s.score=-8
    fmt.Println(*s)

}
func main(){
    stu:=student7{"春哥",8,-5}
    stu1:=student7{
        name:  "春哥2号",
        age:   28,
        score: 100,
    }
    //值传递
    //如果想要修改实参中的值就要地址传递,使用指针进行地址传递
    stu.Print()
    fmt.Println(stu)
    stu1.Print()
    fmt.Println(stu1)
}



输出结果
{春哥 8 -8}
{春哥 8 -8}
{春哥2号 28 -8}
{春哥2号 28 -8}

方法的继承

  • 子类可以继承父类 可以继承属性和方法
  • 父类不能继承子类 不管是属性还是方法
type person01 struct {//父类
    id int
    name string
    age int
}

type student01 struct {//子类
    person01 //匿名字段
    class int
}

func (a *person01)PrintInfo()  {
    //方法建议使用指针类型
    a.id=3
    fmt.Printf("编号%d\n",a.id)
    fmt.Printf("编号%s\n",a.name)
    fmt.Printf("编号%d\n",a.age)

}

func main() {
    var a person01
    a=person01{1,"good boy",18}
    a.PrintInfo()
    //子类可以继承父类 可以继承属性和方法
    //父类不能继承子类 不管是属性还是方法
    s:=student01{person01{2,"du",2},100}
    s.PrintInfo()

方法值和方法表达式

后期开发中的过程 闭包中用到

type person10 struct {
    name string
    age int
    id int
}
//接受者都是p,方法名不能重名

func (p person10)PrintInfo1()  {
    fmt.Printf("%p,%v\n",&p,p)
}
//建议使用指针类型

func (p *person10)PrintInfo2()  {
    fmt.Printf("%p,%v\n",p,*p)
}

func main() {

    p:=person10{"xz",19,1}
    p.PrintInfo1() //0xc0000463e0,{xz 19 1}
    p.PrintInfo2() //0xc0000463c0,{xz 19 1}

    fmt.Printf("%T\n",p.PrintInfo1) //类型是func()


    //方法值  隐式传递 隐藏的是接受者 绑定实力
    //var pfunc1 func()
    //对象相同,但是函数类型不同  不能赋值
    //函数类型相同 可以赋值

    pfunc1:=p.PrintInfo1
    pfunc1()    //0xc000046460,{xz 19 1}
    //pfunc1()等同于p.PrintInfo2()


    //方法表达式 显示传参
    pfunc2:=person10.PrintInfo1
    pfunc2(p)
    pfunc3:=(*person10).PrintInfo1
    pfunc3(&p)


}

接口

接口是规范或者一种标准

  • 定义和使用
    type 接口名er interface
    1.如何使用接口
    接口定义的规则在方法中必须实现
package main

import "fmt"

//先定义接口 一般接口以er结尾 根据接口实现功能

type Humaner interface {
    //方法的声明
    sayhi()
}

type student11 struct {
    name string
    age int
    score int
}

func (s *student11)sayhi()  {
    fmt.Printf("大家好我是%s,我今天%d岁,我这次考了%d分\n",s.name,s.age,s.score)
}

type teacher11 struct {
    name string
    age int
    subject string
}
func (s *teacher11)sayhi()  {
    fmt.Printf("大家好我是%s,我今天%d岁,我这次教%s课",s.name,s.age,s.subject)
}

func main() {
    //定义接口变量
    var h Humaner
    //接口是一种数据类型,可以接受满足对象的信息
    //接口是虚的 方法是实的
    //方法只负责定义规则 方法实现规则
    //接口定义的规则在方法中必须实现
    a:=student11{"张三",18,100}
    //将对象信息赋值给接口类型变量 满足接口中的方法的声明格式
    h=&a
    h.sayhi()
    t:=teacher11{name:"李华", age:45,subject: "体育"}
    fmt.Printf("%T\n",h) //*main.student11
    h=&t
    h.sayhi()




    //a:=student11{"张三",18,100}
    //a.sayhi()
    //t:=teacher11{
    //  name:    "李华",
    //  age:     45,
    //  subject: "体育",
    //}
    //t.sayhi()

}

接口的多态

感觉非常好用,比之前的方法简单
多态的具体实现方法:就是新建一个函数func 函数名(a任意名字 接口){a任意名字.方法名},将接口作为函数参数,传入方法,而后在主方法中用函数将值的地址传进来,大概也许应该是这样的吧

package main

import "fmt"

//先定义接口 一般接口以er结尾 根据接口实现功能

type Humaner interface {
    //方法的声明
    sayhi()
}
//多态的实现
//将接口作为函数参数 实现多态

func sayhello(h Humaner){
    h.sayhi()

}

type student11 struct {
    name string
    age int
    score int
}

func (s *student11)sayhi()  {
    fmt.Printf("大家好我是%s,我今天%d岁,我这次考了%d分\n",s.name,s.age,s.score)
}

type teacher11 struct {
    name string
    age int
    subject string
}
func (s *teacher11)sayhi()  {
    fmt.Printf("大家好我是%s,我今天%d岁,我这次教%s课",s.name,s.age,s.subject)
}

func main()  {
    a:=student11{"张三",18,100}
    //调用多态函数
    sayhello(&a)
    t:=teacher11{name:"李华", age:45,subject: "体育"}
    sayhello(&t)

}

计算器例子

package main

import "fmt"

type operater interface {
    //方法声明  返回值
    result() int
}

type operate struct {//父类
    num1 int
    num2 int
}
type add struct {//加法子类
    operate
}

func (a *add)result() int {
    return a.num1+a.num2
}
type del struct {//减法子类
    operate
}

func (d *del)result() int {
    return d.num1-d.num2

}
//多态的实现
func jishuang(j operater)  {
    v:=j.result()       //要用变量为接受返回值
    fmt.Println(v)

}

func main() {
    //两种写法
    //1.
    //var c add
    //c.num1=12
    //c.num2=13
    //g:=c.result()//返回值需要一个变量来接受
    //fmt.Println(g)

    //2.
    //普通的接口使用
    var o operater
    a:=add{operate{1,2}}
    o=&a
    b:=o.result()
    fmt.Println(b)
    //b:=a.result() //返回值需要一个变量来接受
    //fmt.Println(b)
    d:=del{operate{34,5}}
    o=&d
    o.result()
    //f:=d.result()
    //fmt.Println(f)


    //多态实现
    jishuang(&a)
    jishuang(&d)


}

接口的继承与转换

  • 接口的继承:与其他的继承差不多,在一个接口中加入另一个接口并追加新的东西,比如下面代码的sing,而后通过函数的方法去实现

  • 接口的转换:humaner1是子集,person2是超集,超集可以把值赋给子集,而反过来不行

type Humaner1 interface {//子集
    //方法的声明
    sayhi()
}

type personer2 interface {//超集
    Humaner1
    sing(string)
}

type student12 struct {
    name string
    age int
    score int
}

func (s *student12)sayhi()  {
    fmt.Printf("大家好我是%s,我今天%d岁,我这次考了%d分\n",s.name,s.age,s.score)
}

func (s *student12)sing(name string)  {
    fmt.Println("我为大家唱歌",name)

}

type teacher12 struct {
    name string
    age int
    subject string
}
func (s *teacher12)sayhi()  {
    fmt.Printf("大家好我是%s,我今天%d岁,我这次教%s课",s.name,s.age,s.subject)
}

func main() {
    //接口类型变量定义
    var h Humaner1
    var stu student12=student12{
        name:  "张三",
        age:   20,
        score: 20,
    }
    h=&stu
    h.sayhi()

    var p personer2
    p=&stu
    p.sayhi()
    p.sing("wullllli")
    
    //接口的转换 humaner1是子集,person2是超集,超集可以把值赋给子集,而反过来不行


}
空接口

接口类型可以接受任意类型的数据
var i []interface{}接口类型的切片

类型断言

着重掌握第一种

  • comma-ok断言
    value,ok=element.(T)
    value是变量的值(任意名字),ok是bool类型,element是interface变量,T是断言的类型
func main001()  {
    var i []interface{}
    i= append(i,10,3.144545,"asdsad",tttttt)
        for  _,v := range i{
            //fmt.Println(v)
            if data,ok:=v.(int);ok{
                fmt.Println("这是整型数据",data)

            }else if data,ok:=v.(float64);ok{
                fmt.Println("这是浮点数据",data)

            }else if data,ok:=v.(string);ok{
                fmt.Println("这是字符数据",data)

            }else if data,ok:=v.(func());ok{
                fmt.Println("这是函数数据",data)

            }
    }

}
  • switch测试
func main(){
    var i []interface{}
    i= append(i,10,3.144545,"asdsad",tttttt)
    for  _,v := range i{
        switch data:=v.(type) {
        case int:
            fmt.Println("整型数据",data)
        case string:
            fmt.Println("这是字符数据",data)
        case float64:
            fmt.Println("这是浮点数据",data)
        case func():
            fmt.Println("这是函数数据")
            tttttt()
        }
    }
}

你可能感兴趣的:(Golang面向对象编程 匿名字段 方法 接口)