Golang - 面对"对象"

1. 简介

  • go语言对于面向对象的设计非常简洁而优雅
  • 没有封装、继承、多态这些概念,但同样通过别的方式实现这些特性
  • 封装:通过方法实现
  • 继承:通过匿名字段实现
  • 多态:通过接口实现

2. 匿名字段

go支持只提供类型而不写字段名的方式,也就是匿名字段,也称为嵌入字段

//package 声明开头表示代码所属包
package main import "fmt" //定义人的结构体
type Person struct {
name string
sex string
age int
} //学生
type Student struct {
//匿名字段
//默认Student包含了Person所有字段
Person
id int
addr string
} func main() { s2 := Student{Person:Person{"约汉","female",10},id:2}
fmt.Println(s2)
} //{{约汉 female 10} 2 }

同名字段的情况

//package 声明开头表示代码所属包
package main import "fmt" //定义人的结构体
type Person struct {
name string
sex string
age int
} //学生
type Student struct {
//匿名字段
//默认Student包含了Person所有字段
Person
id int
addr string
//同名字段
name string
} func main() {
var s Student
//就近赋值
s.name = "约汉"
fmt.Println(s)
//若给外面赋值
s.Person.name = "接客"
fmt.Println(s)
} //{{ 0} 0 约汉}
//{{接客 0} 0 约汉}

所有的内置类型和自定义类型都是可以作为匿名字段去使用

package main

import "fmt"

//定义人的结构体
type Person struct {
name string
sex string
age int
} //自定义类型
type mystr string //学生
type Student struct {
//匿名字段
//默认Student包含了Person所有字段
Person
//内置
int
mystr
} func main() {
//初始化
s1 := Student{Person{"约汉","male",18},1,"bj"}
fmt.Println(s1)
fmt.Println(s1.name)
}

指针类型匿名字段

//package 声明开头表示代码所属包
package main import "fmt" //定义人的结构体
type Person struct {
name string
sex string
age int
} //学生
type Student struct {
//匿名字段
//默认Student包含了Person所有字段
*Person
//内置
id int
addr string
} func main() {
s1 := Student{&Person{"约汉","male",18},1,"bj"}
fmt.Println(s1)
fmt.Println(s1.name)
} //{0xc0420661e0 1 bj}
//约汉

3. 方法

4. 包和封装

5. 接口

  • 在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数
  • 这种带有接收者的函数,我们称为方法,本质上,一个方法则是一个和特殊类型关联的函数
  • 方法的语法如下
  • func (接收参数名 接收类型) 方法名(参数列表)(返回值)
  • 可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法
  • 接收类型可以是指针或非指针类型
  • 为类型添加方法(为基础类型添加方法和为结构体类型添加方法)
    • 基础类型

        //package 声明开头表示代码所属包
      package main import "fmt" //任务:定义方法实现2个数相加 type MyInt int //传统定义方式,面向过程
      func Add(a, b MyInt) MyInt {
      return a + b
      } //面向对象
      func (a MyInt) Add(b MyInt) MyInt {
      return a + b
      } func main() {
      var a MyInt = 1
      var b MyInt = 1
      fmt.Println("Add(a,b)=", Add(a, b))
      //调用面向对象的方法
      fmt.Println("a.Add(b)=",a.Add(b))
      } //Add(a,b)= 2
      //a.Add(b)= 2
    • 结构体类型

        //package 声明开头表示代码所属包
      package main import "fmt" type Person struct {
      name string
      sex string
      age int
      } //为Person添加方法
      func (p Person) PrintInfo() {
      fmt.Println(p.name, p.sex, p.age)
      } func main() {
      p := Person{"接客", "male", 18}
      p.PrintInfo()
      }
    • 值语义和引用语义

        //package 声明开头表示代码所属包
      package main import "fmt" type Person struct {
      name string
      sex string
      age int
      } //设置指针作为接收者的方法,引用语义
      func (p *Person) SetInfoPointer() {
      (*p).name = "接客"
      p.sex = "female"
      p.age = 22
      } //值作为接收者,值语义
      func (p Person) SetInfoValue() {
      p.name = "约汉"
      p.sex = "male"
      p.age = 20
      } func main() {
      //指针作为接收者的效果
      p1 := Person{"撸死", "male", 19}
      fmt.Println("函数调用前=", p1)
      (&p1).SetInfoPointer()
      fmt.Println("函数调用后=", p1)
      fmt.Println("================寂寞的分割线=================") //值作为接收者的效果
      p2 := Person{"约汉", "male", 18}
      fmt.Println("函数调用前=", p2)
      p2.SetInfoValue()
      fmt.Println("函数调用后=", p2)
      } //函数调用前= {撸死 male 19}
      //函数调用后= {接客 female 22}
      //================寂寞的分割线=================
      //函数调用前= {约汉 male 18}
      //函数调用后= {约汉 male 18}
    • 方法的继承

        package main
      
        import "fmt"
      
        type Person struct {
      name string
      sex string
      age int
      } //为Person定义方法
      func (p *Person) PrintInfo() {
      fmt.Printf("%s,%s,%d\n",p.name,p.sex,p.age) } type Student struct {
      Person
      id int
      addr string
      } func main() {
      p :=Person{"接客","male",18}
      p.PrintInfo()
      //学生也去调,方法继承
      s := Student{Person{"接客","male",18},2,"bj"}
      s.PrintInfo()
      }
    • 方法的重写

        package main
      
        import "fmt"
      
        type Person struct {
      name string
      sex string
      age int
      } //为Person定义方法
      func (p *Person) PrintInfo() {
      fmt.Printf("%s,%s,%d\n", p.name, p.sex, p.age)
      } type Student struct {
      Person
      id int
      addr string
      } //Student定义方法,实际上就相当于方法重写
      func (s *Student) PrintInfo() {
      fmt.Printf("Student:%s,%s,%d\n", s.name, s.sex, s.age)
      } func main() {
      p := Person{"接客", "male", 18}
      p.PrintInfo()
      //学生也去调,方法继承
      s := Student{Person{"接客", "male", 18}, 2, "bj"}
      s.PrintInfo()
      //显式调用
      s.Person.PrintInfo()
      }
    • 方法值和方法表达式

        package main
      
        import "fmt"
      
        type Person struct {
      name string
      sex string
      age int
      } func (p *Person) PrintInfoPointer() {
      //%p是地址,%v是值
      fmt.Printf("%p,%v\n", p, p)
      } func main() {
      p := Person{"接客", "male", 18}
      //传统的调用方法的方式
      p.PrintInfoPointer()
      //使用go方法值特性调用
      pFunc1 := p.PrintInfoPointer
      pFunc1()
      //使用go方法表达式调用
      pFunc2 := (*Person).PrintInfoPointer
      pFunc2(&p)
      }

练习:创建属性的getter和setter方法并进行调用

	package main

	import "fmt"

	type Dog struct {
name string
//1公 0母
sex int
} //封装dog的方法
//setter
func (d *Dog) SetName(name string) {
d.name = name
} //getter
func (d *Dog) GetName() string {
return d.name
} //咬人
func (d *Dog) bite() {
fmt.Printf("让本汪%s 来给你上课...", d.name)
} func main() {
d := Dog{"二哈", 1}
d.bite()
}

4. 包和封装

  • 方法首字母大写:public
  • 方法首字母小写:private
  • 为结构体定义的方法必须放在同一个包内,可以是不同的文件
  • 上面代码复制到test包中,在test02包中进行调用,需要调用的方法名首字母大写

5. 接口

  • go语言中,接口(interface)是一个自定义类型,描述了一系列方法的集合

  • 接口不能被实例化

  • 接口定义语法如下

  • type 接口名 interface{}

  • PS:接口命名习惯以er结尾

  • 接口定义与实现

      package main
    
      import "fmt"
    
      //定义人的接口
    type Humaner interface {
    //说话
    Say()
    } //学生结构体
    type Student struct {
    name string
    score int
    } //Student实现Say()方法
    func (s *Student) Say() {
    fmt.Printf("Student[%s,%d] 瞌睡不断\n", s.name, s.score)
    } type Teacher struct {
    name string
    group string
    } //老师实现接口
    func (t *Teacher) Say() {
    fmt.Printf("Teacher[%s,%s] 毁人不倦\n", t.name, t.group)
    } //自定义类型
    type MyStr string //自定义类型实现方法
    func (str MyStr) Say() {
    fmt.Printf("MyStr[%s] 同志醒醒,还有个bug\n", str)
    } func WhoSay(i Humaner) {
    i.Say()
    } func main() {
    s := &Student{"约汉", 88}
    t := &Teacher{"撸死", "Go语言"}
    var tmp MyStr = "接客" s.Say()
    t.Say()
    tmp.Say() //go的多态,调用同一个接口,不同表现
    WhoSay(s)
    WhoSay(t)
    WhoSay(tmp) //make()创建
    x := make([]Humaner, 3)
    x[0], x[1], x[2] = s, t, tmp
    for _, value := range x {
    value.Say()
    }
    }
    • 接口继承

        package main
      
        import "fmt"
      
        //定义人的接口
      type Humaner interface {
      //说话
      Say()
      }
      type Personer interface {
      //等价于写了Say()
      Humaner
      Sing(lyrics string)
      } //学生结构体
      type Student struct {
      name string
      score int
      } //Student实现Say()方法
      func (s *Student) Say() {
      fmt.Printf("Student[%s,%d] 瞌睡不断\n", s.name, s.score)
      } func (s *Student) Sing(lyrics string) {
      fmt.Printf("Student sing[%s]!!\n", lyrics)
      } func main() {
      s := &Student{"约汉", 88}
      var p Personer
      p = s
      p.Say()
      p.Sing("互撸娃")
      }
    • 空接口:空interface{}不包含任何方法,空接客可以存储任意类型的值

    • 类型查询

      • comma-ok断言

          package main
        
          import "fmt"
        
          //空接口
        type Element interface{} type Person struct {
        name string
        age int
        } func main() {
        //切片
        list := make([]Element, 3)
        //int
        list[0] = 1
        list[1] = "Hello"
        list[2] = Person{"luhan", 18}
        //遍历
        for index, element := range list {
        //类型断言:value ,ok = element.(T)
        //value 是变量的值,ok是返回的布尔值,element是接口变量,T是断言类型
        if value, ok := element.(int); ok {
        fmt.Printf("list[%d]是int类型,值是%d\n", index, value)
        } else if value, ok := element.(int); ok {
        fmt.Printf("list[%d]是int类型,值是%d\n", index, value)
        } else if value, ok := element.(Person); ok {
        fmt.Printf("list[%d]是Person类型,值是[%s,%d]\n",
        index, value.name, value.age)
        } else {
        fmt.Printf("list[%d]是其他类型\n", index)
        }
        }
        }
      • switch测试

        package main
        
        import "fmt"
        
        //空接口
        type Element interface{} type Person struct {
        name string
        age int
        } func main() {
        //切片
        list := make([]Element, 3)
        //int
        list[0] = 1
        list[1] = "Hello"
        list[2] = Person{"luhan", 18}
        //遍历
        for index, element := range list {
        switch value := element.(type) {
        case int:
        fmt.Printf("list[%d]是int类型,值是%d\n", index, value)
        case string:
        fmt.Printf("list[%d]是string类型,值是%s\n", index, value)
        default:
        fmt.Printf("list[%d]是其他类型\n", index)
        }
        }
        }

Golang - 面对"对象"的更多相关文章

  1. golang面对对象

  2. 跟着百度学PHP[4]OOP面对对象编程-7-OOP的一些关键子讲解

    面对对象常用的一些关键子:http://www.cnblogs.com/xishaonian/p/6146794.html排版不是很好望见谅. THE END

  3. python面对对象编程----2:__init__

    面对对象编程估计我们最早接触到的就是__init__了,也就是实例的初始化处理过程: 1:来看看最基础的__init__ class Card(object): #抽象类Card,并不用于实例化 de ...

  4. Javascript面对对象. 第一篇

    Javascript,有两个种开发模式: 1.函数式(过程化)2.面对对象(oop),面对对象语言有一个标志,就是类,而通过类可以创建任何多个属性和方法,而Ecmascript没有类的概念,因此它的对 ...

  5. Java入门——(2)面对对象(上)

      关键词:面对对象.类..构造方法.this.static.内部类   一.面对对象的概念:把解决的问题安装一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题.其特点可概括为封装性.继承 ...

  6. Day-8: 面对对象编程

    面对过程的程序设计方法意在将函数分成子函数,再依次调用这些函数来解决问题. 而面对对象的程序设计方法,来源于自然界,类是实例的抽象,实例是类的具体.自定义出来的对象是类,而所有的数据都可以看成是对象, ...

  7. java基础--面对对象

    面对对象--概述 什么是对象? +---->对象可以泛指一切现实中存着的事物 +---->类是对象的抽象集合 什么是面对对象? +--->万物皆对象,面对对象实际就是人与万物接触== ...

  8. Python进阶_面对对象&面对过程

    这节主要讲面对对象与面对过程两种编程思想的主要区别. 一. 简单对比 面向过程是一种基础的方法,它考虑的是实际的实现步骤,一般情况下,面向过程是自顶向下逐步求精,其最重要的是模块化的思想方法. 面向对 ...

  9. python面对对象(不全解)

    面对对象:以人类为例,人类通用功能:吃喝拉撒,就可以封装成一个类,不同功能:嫖赌毒,就是对象的不同功能.继承,多态… 上码 class Person(object): def __init__(sel ...

随机推荐

  1. MFC的UI更新机制和加速键的创建

    近期在看<MFC Windows程序设计>这本书,正好看到更新菜单中的菜单项和加入菜单项的加速键这方面的内容,下面总一下总结. MFC提供的更新菜单项的机制例如以下: 通过消息映射表中的O ...

  2. SolrCloud 分布式集群部署步骤

    https://segmentfault.com/a/1190000000595712 SolrCloud 分布式集群部署步骤 solr solrcloud zookeeper apache-tomc ...

  3. java的死锁学习

    学习java的死锁写的代码 也是看书上的然后自己敲了一个 <span style="font-size:18px;">package synchronization.j ...

  4. U4704 函数

    U4704 函数 题目背景 设gcd(a,b)为a和b的最大公约数,xor(a,b)为a异或b的结果. 最大公约数 异或 题目描述 kkk总是把gcd写成xor.今天数学考试恰好出到了gcd(a,b) ...

  5. Entity Framework Utility .ttinclude File

    https://msdn.microsoft.com/en-us/library/ff477603(v=vs.100).aspx This topic provides an overview of ...

  6. 【概念的辨异】—— ISO C 与 POSIX C(C standard library 与 C POSIX library)

    ISO C 表示 C Standard Library,也就是 C 标准库. 二者的主要区别在于: POSIX 是 C 标准库的超集(也即是从内容上,C 标准库是 POSIX 库的一部分,POSIX ...

  7. 简述RTMPDump与编译移植

    RTMPDump主页 ,RTMPDump库主要包含三部分: 1.一个基本的客户端程序 2.两个服务器程序(rtmpsrv.rtmpsuck) 3.一个支持rtmp协议的库—librtmp 下载RTMP ...

  8. 杂项:Web API

    ylbtech-杂项:Web API 今天的web计算平台包含了广泛的功能,其中的大部分均可以通过API(应用程序编程接口)访问. 从简单的社会书签服务del.icio.us,到复杂得多的amazon ...

  9. Java多线程技术-Lock/Condition

    在java1.5中Lock对象来实现同步的效果,而且使用上更方便. 使用ReentrantLock实现同步 public class MyService { private Lock lock = n ...

  10. WebService的概念

    一.序言 大家或多或少都听过 WebService(Web服务),有一段时间很多计算机期刊.书籍和网站都大肆的提及和宣传WebService技术,其中不乏很多吹嘘和做广告的成 分.但是不得不承认的是W ...