[+]文章目录

面向对象

Go 的优势

  • 可以编译成机器码,不依赖其他库
  • 静态类型语言,有动态语言的感觉。静态语言就是可以在编译的时候检查出来隐藏的大多数问题,动态语言的感觉-就是很多的包可以使用,写起来效率很高
  • 语言层面支持并发,这是 Go 语言的最大的特色,天生支持并发(天生的基因和后来的整容是有区别的)
  • 内置 runtime,支持垃圾回收机制
  • 简单易学,有C语言的基因,Go 语言有 25 个关键字,但是表达能力极强
  • 丰富的标准库,内置大量库,特别是网络库非常强大
  • 内置强大工具,使 review 变的简单,可以使代码格式一模一样
  • 跨平台编译,可以不依赖与系统信息
  • 内置 C 支持

Go 适合

  • 服务器编程
  • 分布式系统,数据库代理器
  • 网络编程
  • 云平台,国内的七牛云存储的关键服务就是使用Go语言开发的

Go 的缺点

  • Go的 import 包不支持版本,升级容易导致项目不可运行,所以需要自己控制相应的版本信息
  • Go的 gotoutine 一旦启动,不同的 goroutine 之间切换不收程序的控制,runtime 调度的时候,需要严谨的逻辑,
  • 不然 goroutine 休眠,过一段时间逻辑结束了,突然冒出来又执行了,会导致逻辑出错等情况
  • GC 延迟有点大

Go 语言的面向对象特性

Go 语言的大多数类型都是值语义,并且都可以包含对应的操作方法。在需要的时候,你可以给内置类型“增加”新方法。儿在实现某个具体的接口时,无需从该接口继承,只需要实现该接口要求的所有方法即可。任何类型都可以被Any 类型引用。Any 类型就是空接口,即interface{}。

给类型添加方法

type Integer int

func (a Integer) Less(b Integer) bool {
    return a < b
}

func main() {
    fmt.Println("Hello")
    var a, b Integer = 1,2
    fmt.Println(a,b)
    res := a.Less(b)
    fmt.Println(res)
}

上面给 Integer 添加了一个 Less 方法第一个 a 是给 a 添加方法,b 是参数,bool 是函数返回值。

在 Go 语言中,面向对象的神秘面纱不复存在,不像 C++ 和 Java,方法都默认有一个隐藏的 this 指针,Python 中方法中的 self 和 this 指针的作用是一样的。Go 中方法施加的目标(对象),显示传递;不需要非得是指针,也不用非得叫this。只有在需要修改对象的时候才有必要使用指针。比如:

func (a *Integer) Add(b Integer) {
    *a += b
}

Go 语言和 C 语言是一样的,都是基于值传递的。要想修改变量的值,只能传递指针。

值语义和引用语义

Go 语言大多数类型都基于值语义:基本类型+符合类型(数组、结构体、指针)。和 C 语言不同的,数组的传递也是基于值语义的,而且很纯粹。比如:

var arrayA [3]int = [3]int{1,2,3}
arrayB := arrayA
arrayB[1]++
fmt.Println(arrayA,arrayB)

会看到输出,对 B 中元素的操作,对 A 并没有任何影响。这表明在将 A 赋值给 B 的时候是数组内容的完整复制,如果想要表达引用,需要使用指针: arrayB := &arrayA

数组切片、map、channel、接口看起来想引用类型

结构体

Go 中的结构体和其他语言的类有相同的地位,但是 Go 语言中没有继承在内的大量面向对象的特性,只保留了组合(composition)这个最基础的特性。比如下面的例子对 log 的使用

type Job struct {
    Command string
    *log.Logger
}

func NewJob(command string, logger *log.Logger) *Job {
    return &Job{command,logger}
}

func (job *Job)Start(){
    job.Println("Starting now....")
    job.Println("end")
}

func main() {
    mylog := log.New(os.Stdout, "",log.LstdFlags)
    j := NewJob("test",mylog)
    j.Start()
}

定义的 Job 结构体包含一个匿名的 log.Logger 指针,在合适的赋值之后可以在 Job 类型的所有成员方法中可以很舒适的借用所有 log.Logger 提供的方法。类似于 Java 和 C++ 中继承了 log.Logger

Go 语言中并没有其他语言中的 public 等权限访问控制的关键字。要使某个符号对其他包可见,需要将该符号定义为以大写字母开头,就想上面定义的 Job 结构体首字母需要大写。成员方法的访问性遵循同样的规则,如果上面的 Start 函数定义为 start,则该函数只能在该类型所在的包内使用。

接口

Go 语言中的接口不需要像 C++ 和 Java 中的使用:或者 implements 关键字来实现接口,在 Go 语言中,一个类只需要实现了接口要求的所有函数,那么这个类就实现了该接口。下面的例子:

//定义一个文件接口
type IFile interface {
    Read(buf []byte) (n int, err error)
    Write(buf []byte) (n int, err error)
    Close() error
}

type IReader interface {
    Read(buf []byte) (n int, err error)
}

type IWriter interface {
    Write(buf []byte) (n int, err error)
}

type ICloser interface {
    Close() error
}

//定义文件类
type File struct {
    filename string
    fid int16
}
//定义文件的几个方法
func (f *File)Read(buf []byte) (n int, err error){
    fmt.Println("File Opened")
    return 0,nil
}
func (f *File)Write(buf []byte) (n int,err error) {
    fmt.Println("File Writed")
    return 0,nil
}
func (f *File)Close() error {
    fmt.Println("File Closed")
    return nil
}

func main() {
    bytes := []byte{0,1,2,3,4,5,6,7,8,9}
    var file1 IFile = new(File)
    file1.Read(bytes)

    var file2 IReader = new(File)
    file2.Read(bytes)

    var file3 IWriter = new(File)
    file3.Write(bytes)

    var file4 ICloser = new(File)
    file4.Close()
}

File 类实现了上面的所有接口,所以可以直接进行赋值。Go 语言的接口是非侵入式接口:

  • Go 语言标准库不需要绘制类库的继承图,在 Go 中,类的继承树并无意义,只有知道这个类实现了那些方法,每个方法是什么含义即可
  • 实现类的时候,只需要关系自己应该提供那些方法,不用再纠结接口需要拆的多细才合理,按需定义
  • 不用为了实现一个即可而导入一个包,因为多引用一个外部的包就意味着更多的耦合

接口还可以通过组合来实现:

type IReaderWriter interface {
    IReader
    IWriter
}

和下面的实现是一样的:

type IReaderWriter interface {
    Read(buf []byte) (n int, err error)
    Write(buf []byte) (n int, err error)
}

Go 语言中的 Any 类型

Java 语言中所有的对象都继承自 Object,而 Go 语言中的任何对象的实例都满足空接口 interface{},所以 interface{}看起来就想指向任何对象的 Any 类型。

var v1 interface{} = 1
var v2 interface{} = "abc"
var v3 interface{} = &v2
var v4 interface{} = struct { x int }{1}

面向对象三大特性

有过 C++ 语言学习经历的朋友都知道,面向对象主要包括了三个基本特征:封装、继承和多态。封装,就是指运行的数据和函数绑定在一起,C++ 中主要是通过 this 指针来完成的;继承,就是指 class 之间可以相互继承属性和函数;多态,主要就是用统一的接口来处理通用的逻辑,每个 class 只需要按照接口实现自己的回调函数就可以了。

作为集大成者的 Go 语言,自然不会在面向对象上面无所作为。相比较 C++、java、C# 等面向对象语言而言,它的面向对象更简单,也更容易理解。下面,我们不妨用三个简单的例子来说明一下 go 语言下的面向对象是什么样的。

封装特性

package main  

import "fmt"  

type data struct {  

    val int  
}  

func (p_data* data)set(num int) {  

    p_data.val = num  
}  

func (p_data* data)show() {  

    fmt.Println(p_data.val)  
}  

func main() {  

    p_data := &data{4}  
    p_data.set(5)  
    p_data.show()  

}  

继承特性

package main  

import "fmt"  

type parent struct {  

    val int  
}  

type child struct {  

    parent  
    num int  
}  

func main() {  

    var c child  

    c = child{parent{1}, 2}  
    fmt.Println(c.num)  
    fmt.Println(c.val)  

}  

多态特性

package main  

import "fmt"  

type act interface {  

    write()  
}  

type xiaoming struct {  

}  

type xiaofang struct {  

}  

func (xm *xiaoming) write() {  

    fmt.Println("xiaoming write")  
}  

func (xf *xiaofang) write() {  

    fmt.Println("xiaofang write")  
}  

func main() {  

    var w act;  

    xm := xiaoming{}  
    xf := xiaofang{}  

    w = &xm  
    w.write()  

    w = &xf  
    w.write()  
}  

« 前一篇