首页 » Go » 正文

Go 语言集训(三):面向对象

在Go语言中,面向对象和面向过程是两种不同的方式。

func (a Integer) Less (b Integer) bool {  //面向对象
    return a < b
}

func Integer_Less(a Integer, b Integer) bool {//面向过程
    return a < b
}

GO语言中有4个类型比较特别,看起来像引用类型。

  1. 数组切片:指向数组的一个去见
  2. map:及其常见的数据结构,提供键值查询能力。Map本质是一个字典指针
  3. channel:执行体(goroutine)间的通信设施
  4. 接口(interface):对一组满足某个契约的类型的抽象
    Channel和Map类似,本质上是一个指针。将他们设计为引用类型而不是统一的值类型的原因是,完整复制一个channel或者map并不是常规需求。

匿名组合

type Job struct {
    Command String 
    *log.Logger
}

func(job *Job) Start() {
    job.Log("Starting now...")
    job.Log("started")
}

在合适赋值后,我们在JOB类型的所有成员方法中可以很舒适地借用所有log.Logger提供的方法。对于Job实现者来讲,他甚至根本不用意识到log.Logger类型的存在,这就是匿名组合的美丽。
需要注意的是,不管是非匿名的类型组合还是匿名组合,被组合的类型所包含的方法虽然都升级成外部这个组合类型的方法,但是其实他们被组合方法调用时接收者并没有改变。比如Job例子,即使这个组合后调用的方式变成了job.Log(…),但Log函数的接收者任然是log.Logger指针,因此在Log中不可能访问到Job的其他成员方法和变量。

type X struct {
    Name string
}

type Y struct {
    X
    Name string
}

接口组合中名字冲突时,所有Y类型的Name成员都只会访问到最外层的那个Name变量。X.Name相当于隐藏了起来。

type Logger struct{
    Level int
}
type Y struct{
    *Logger
    Name string
    *log.Logger
}//这里会有问题,可能收到编译错误,但如果定义后没有再用过,也不会产生错误。因为Y类型存在两个名为Logger的成员。虽然类型不同。

可见性

要使某个符号对其他包可见,需要将该符号定义为以答谢字母开头。

type Rect struct {
    X,Y float64
    Width,Height float64
}//这样Rect类型的成员全部被导出了

func (r *Rect) area() float64 {//包内可见
    return r.Width * r.Height 
}

Go语言中符号的可访问新是包一级的而不是类型一级的。在上面例子中,area是Rect内部方法,但同一个包中的其他类型也可以访问到它。这样做很粗犷,但很实用。如果GO语言的可访问性是类型一级的,少不了加上friend这样的关键字,标识两个类是朋友关系,可以访问彼此的私有成员。

接口赋值

  1. 将对象实例赋值给接口
  2. 将一个接口赋值给另外一个接口
    A(小) = B(大)

接口查询

var file1 Wirter = ..
if file5,ok := file.(two.IStream); ok {
    ...
}

if file6,ok := file.(*File); ok {
    ...
}

完整案例