Go基础编程---面向对象

面向对象

Go中没有发封装、继承、多态,但是可以通过方法、匿名字段、接口实现,Go中偏向于面向接口编程

匿名字段(继承)

一般定义结构体时字段名与其类型一一对应,但是Go也支持 只提供类型,而不写字段名的方式,也就是匿名字段,也称嵌入字段,当匿名字段也是一个结构体的时候,那么这个结构体所拥有的全部字段都被隐式引入当前定义的这个结构体


type Animal struct {
    Name  string
    Age   int
    Color string
}
type Cat struct {
    Animal
    Types string
}

func main() {
    var cat Cat
    fmt.Println(cat)         // {{ 0 } }
    fmt.Printf("%+v\n", cat) // {Animal:{Name: Age:0 Color:} Types:}
    // 结构体初始化的几种方式
    // 部分成员初始化
    cat1 := Cat{Animal: Animal{Name: "zz", Color: "red"}, Types: "龙猫"}
    fmt.Printf("%+v\n", cat1) // {Animal:{Name:zz Age:0 Color:red} Types:龙猫}
    // 全部成员初始化
    cat2 := Cat{Animal{"gg", 2, "red"}, "老虎猫"}
    fmt.Printf("cat2 = %+v\n", cat2) // cat2 = {Animal:{Name:gg Age:2 Color:red} Types:老虎猫}

    // 结构体成员操作---取值
    /*cat2.Name        // -> gg
    cat2.Animal.Name // -> gg
    cat2.Types */ // -> 老虎猫, 若Animal中也有Types,则取值就近原则
    // 结构体成员操作---赋值
    cat2.Name = "CC"                 // -> "CC"
    cat2.Animal.Name = "DD"          // -> "DD"
    fmt.Printf("cat2 = %+v\n", cat2) // cat2 = {Animal:{Name:gg Age:2 Color:red} Types:老虎猫}

    // 其他匿名字段(非结构体类型,但是应用场景很少)
    // 所有的内置类型和自定义类型都是可以作为匿名字段的
    type myStr string // 自定义类型
    type Dog struct {
        Animal //匿名字段,结构体类型
        myStr  //匿名字段,自定义类型(少用)
        int    //匿名字段,内置类型(少用)
    }
    fmt.Println("----------------------------------------------------")
    // 结构体指针类型
    type Person struct {
        Name string
        Age  int
        Sex  byte
    }
    type Student struct {
        *Person // 匿名字段,结构体指针类型
        Id      int
        Addr    string
    }
    // 结构体指针类型的初始化
    people := Student{&Person{"zhangsan", 12, 1}, 1001, "beijing"}
    fmt.Printf("%+v \n", people) //people = {Person:0xc42000a060 Id:1001 Addr:beijing}
    // 结构体指针类型的操作
    var people1 = new(Person) // 分配空间
    people.Name = "xx"
    fmt.Printf("%+v ,%s \n", people, people.Name) //{Person:0xc42000a060 Id:1001 Addr:beijing} ,xx 
}

方法(封装)

在go中一个对象其实也就是一个简单的值或者是一个变量,在这个对象中会包含一些函数,这种带有接收者的函数,我们称为方法,本质上一个方法则是一个和特殊类型关联的函数
在Go中我们可以给任意自定义类型(包括内置类型、但是不包括指针类型)添加相应的方法,方法总是绑定对象实列

方法语法以及特点

func (receiver ReceiverType) funcName( parameters) (results)
* 参数reciver 可任意命名,如果方法中未使用,可省略参数名
* 参数reciver类型可以式T,或者*T,基本类型T不能是指针或者接口
* 不支持方法重载,也就是说不能定义名字相同但是不同参数的方法,但是只要接收者不一样,那么这2个函数就是不一样的函数
type Ins interface {
    Run()
}
type Inss *int

func (i Ins) Run() {
    //invalid receiver type Ins (Ins is an interface type)
}
func (i Inss) Run() {
    //invalid receiver type Inss (Inss is a pointer type)
}

自定义类型添加方法

type long int // 自定义一个类型,实际就是int型
func (l long) Add(n long) long {
    return l + n
}
func main() {
    //  l, n := 1, 2
    //  result := Add(l, n)
    //  fmt.Println(result) // undefined: Add
    var lo long = 2
    //  var i int
    fmt.Println(lo.Add(1))
    i := lo.Add(6) //cannot use lo.Add(1) (type long) as type int in assignment
    // 强类型,虽然返回的long类型实际是int,但是int类型的变量不能接收long类型的,
    var c = 6  // 自动推断c为int类型
    d := lo.Add(c) //报错不能传递int类型
    //  函数的参数虽然为long型,但是传递的是常量,Go能自动的将int 转为long,如果参数是变量,则有了类型,只要不是long类型就会报错
    fmt.Println(i) // 8
    fmt.Println(d) // cannot use c (type int) as type long in argument to lo.Add
}

结构体类型添加方法

type Person struct {
    Name string
    Sex  byte
    Age  int
}

// 定义一个结构体的方法,结构体类似于class,里面的变量为class的属性,结构体方法
func (p Person) Read() {
    fmt.Println(p.Name, "读书")
}
func (p *Person) SetInfo(name string, sex byte, age int) {
    p.Name = name
    p.Sex = sex
    p.Age = age
}
func main() {
    // 实例化结构体
    var p = Person{"zhangsan", 1, 12}
    p.Read()
    // 实例化结构体
    var p2 = Person{"李四", 1, 12}
    p2.Read()
    var p3 Person // 定义一个Person类型的变量
    p3.SetInfo("王五", 2, 11)
    fmt.Println(p3) //{王五 2 11}
}

值语义和引用语义

值语义: func ( p People) funName (xx){}    // 拷贝的副本
引用语义:func( p *People) funName(xx){}  //传递地址值

方法集

无论对象是指针类型还是值类型,都能调用,因为Go内部做了转换
eg:
type  Po struct{ Name string}
func (p Po) run() {}
func (p *Po) eat() {}
//指针对象
p := &Po{ "gao"}  //p可以调run 和 eat,在调run时内部p转换成了( *p )
//实例对象
p :=Po { "gao"}  //p可以调run 和 eat,在调eat时内部p转换成了( &p )

方法的继承和重写---方法表达式和方法值

结构体组合,除了能继承字段也能继承方法
type Person struct {
    Name string
    Sex  byte
    Age  int
}
type Student struct {
    Person // 不仅仅继承了Person的属性还继承他的Eat方法
    Id     int
}

// 给Person类型定义了一个方法
func (p Person) Eat() {
    fmt.Println(p.Name, "eating")
}

// 给Student 类型也定义一个和Eat方法,导致重写了Peson的Eat方法
func (s Student) Eat() {
    fmt.Println(s.Name, "student is eating")
}
func main() {
    p := Student{Person: Person{Name: "zzz"}}
    p.Eat()        //zzz student is eating
    p.Person.Eat() // zzz eating
    fmt.Println("--------------方法值和方法表达式---------------------")
    pFunc := p.Eat   // 这个就是方法值,调用函数时无需再传递接收者,隐藏了接收者,调用直接 pFunc()即可
    pFuncss :=(Stundent).Eat  // 方法表达式,类型为指针就得加指针 pFuncss(p)
    pFuncss :=(*Student).Eat   // 调用时 pFuncss(&p)
        
}

接口(多态实现)

Go中interface是一个自定义的抽象类型,不能将其实例化,内部只是描述一系列方法的集合

定义: 
type 接口名 interface{
      SayHi(a,b string) string
      ....
}
接口名习惯以er结尾
接口只有方法声明,没有实现,没有数据字段
接口可以匿名嵌入其他接口,或者嵌入到结构中去
接口是用来定义行为的类型,这个被定义的行为通过方法由用户定义的类型实现。实现了这个方法的具体类型就是这个接口类型的实例

接口的实现


type People struct {
    Name string
    Age  int
}
type Teacher struct {
    People
}
type Student struct {
    People
}
type str string
type Worker interface {
    Work()
}

func (strs str) Work() {
    fmt.Println("str")
}
func (t Teacher) Work() {
    fmt.Println(t.Name, "讲课")
}
func (s Student) Work() {
    fmt.Println(s.Name, "学习")
}
// 此函数的参数必须是实现了Worker接口的对象
func work(i Worker) {
    i.Work()
}
func main() {
    // 定义一个worker接口类型不能实例化,只能使得其他实现worker接口的实例赋值给此变量
    var inter Worker
    t := &Teacher{People{"laoshi", 55}}
    s := &Student{People{"xuesheng", 22}}
    var strs str
    inter = t
    inter.Work()
    inter = s
    inter.Work()
    inter = &strs
    inter.Work()
    //var aas int
    //inter = aas //cannot use aas (type int) as type Worker in assignment
    //inter.Work()
    // 调用同一函数,不同表现,多态,多种形态
    work(t)
    work(s)
    work(&strs)
    // 创建一个切片,每个内容都是一个实现了Worker接口的实例
    x := make([]Worker, 3)
    x[0] = t
    x[1] = s
    x[2] = &strs
    for _, v := range x {
        v.Work()
    }
}

接口的赋值(2种情况)

1、将对象实例赋值给接口(要求对象实现了接口的所有方法)
     - 类实例化时指针或者实例区别:
         o: 用new(structName):这个方法得到的是*structName类型,即类的指针类型
         o: 用structName{init para}:这个方法得到的是structName类型,即类的实例类型,不是指针
      -  类在实现接口的时候,要注意定义的时候,一般用类的指针传入,就可以了。   
          因为如果用类的结构体的话,可能会导致“类没有实现接口中某个方法”的错误
          

      
2、将一个接口赋值给另一个接口(假设接口A中定义的所有方法,都在接口B中有定义,   
那么B接口的实例可以赋值给A的对象。反之不成立,除非A和B定义的方法完全一样(顺序不要求),   
这时A和B等价,可以相互赋值。)

接口继承 ---- 接口转换

type  aa  interface{  //子集  可以理解父类
     run ()
}
type  bb interface{   //超集 可以理解子类
      aa // 匿名字段,继承run()
      say()
}
//超集可以转换为子集,反过来不可以
var  iPro bb  // 超集
var  i  aa   // 子集
i = iPro  // 可以
iPro = i // 不可以

空接口(万能类型,可以保存任意类型的值)

var i interface{} = 1
i = "abc"
i = true // 不会报错
func aa(args ...interface{}){
  // 可以接收任意数量,任意类型的参数
}

类型断言--if 和switch 都可以实现

if实现
type Student struct{
    Name string
}
func main(){
    //  set a slice typeof is everything,length is three
    slice := make([]interface{},3)  
    slice[0] = 1   //typeof is int
    slice[1] = "xxx"  // typeof is string
    slice[2] = Student{"names"} // typeof is Student
    // so we back to assert the typeof in slice everyone
    for index, value :range slice{ // value is slice[0],slice[1]...
        //assert
        if data,ok :=value.(int);ok == true{
            //this typeof is int
        }else if data,ok :=value.(string);ok == true{
            //this typeof is string
        }else if data,ok :=value.(Student);ok == true{
            //this typeof is Student
        }
    }
}
switch实现(替换调if判断就ok)
switch data := value.(type){
    case int:
        //type is int
    case string:
        //type is string
    case Student:
        //type is Student
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,605评论 18 399
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,934评论 6 13
  • 平凡的家庭 什么逆袭呢? 2017年高考成绩出来的时候,各大省的高考状元在媒体说说自己的高考之路。满屏的话题新闻,...
    开始的开始1阅读 230评论 2 1
  • 好久没有写一写小书了,今晚难得悠闲,跑来溜达一圈,每当休息的时候,总是会思绪万千,幻想着未来,又期待着明天,翻看许...
    晗姐123阅读 178评论 0 0