许世伟的Go语言基础 第三章总结

第3章 面向对象编程

Go语言没有继承、虚函数、构造析构函数、this指针等。

3.1类型系统

类型系统:

  • 基础类型
  • 复合类型
  • 指向对象的任意类型Any
  • 值语义和引用语义
  • 面向对象
  • 接口

为类型添加方法

go可以为任何类型添加方法(包括内置类型,但不包括指针类型)。

go语言没有隐藏的this指针。也就是方法施加的对象显式传递,不需要非得是指针,也不用非得叫this。

&取地址,*取内容和表示指针。

当需要修改对象时,类方法必须用指针。

func (a *Integer) Add(b Integer){
    *a +=b
}
//不修改对象就不用加指针,保护数据但有内存开销。
func (a Integer) Add(b Integer){
  c := a+b
  fmt.Print(c)
}

值语义和引用语义

go语言大多数类型都是值语义。基本类型,以及数组、结构体、指针都是值语义。

对数组a,b=a是内容的完整复制,如想表达引用需使用指针var b=&a。

以下4个类型是引用类型:

  • 数组切片
  • map
  • channel
  • interface

channel和map本质上是一个指针,考虑到复制channel和map并不是常规要求,所以设计为引用类型而非统一的值类型。

初始化

go没有构造函数。对象创建由全局的创建函数执行(固定的NewXXX命名):

//创建Rect对象,注意结构体是值语义,返回值需取址转成指针。
func NewRect(x,y,width,height float64) *Rect{
  return &Rect{x,y,width,height}
}

匿名组合

go调用类成员的类方法,相当于调用父类的方法。没有继承重写的概念。

type Base struct{}
type Foo struct{
    Base
}
func (foo *Foo) Bar(){
  foo.Base.Bar()
}//相当于继承

指针方式从一个类派生:(匿名组合)

type Foo struct{
    *Base
}
var foo Foo
foo.Bar()
//匿名使用类成员的方法,可以当作继承用。
//构造时需要外部提供一个Base类实例的指针。

需要注意,无论匿名组合还是非匿名组合,调用的接收方并没有改变。被调用的Bar()方法不能访问Foo结构体中除Base结构体以外的其它方法。(缺点和问题)

对于命名冲突问题:

type X struct{
    Name string
}
type Y struct{
    X
    Name string
}
//Y对象只会访问到外层的Name变量,X.Name变量被隐藏起来了。

type Logger struct{}
type Y stuct{
    *Logger
    Name string
    *log.Logger
}
//重名的成员变量会导致编译错误,但如果不都使用,则编译器会忽略这个错误。

可见性

大写包外可见。

go的访问性是包一级而不是类型一级的,类方法也可以被同包的其它类使用。

接口

侵入式接口:实现类需要声明自己实现了某个接口。

go语言是非侵入式接口:只要实现了接口要求的所有函数,就是实现了接口。因百不必关心以下问题:

  • 两个类实现了相同的接口,放在哪个包中才好。
  • 提供哪些接口。

意义:

  • go中,类的继承树并无意义,只需要知道类实现了哪些方法和每个方法的含义。
  • 实现与只需要关心:需要提供哪些方法。不必关注接口拆多细。
  • 不必为了实现接口而导入一个包。引入外部包意味着耦合。

接口赋值(重点)

定义一个接口和实现类:

type Integer int

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

go语言根据

func (a Integer) Less(b Integer) bool

自动生成

func (a *Integer) Less(b Integer) bool{
  return (*a).Less(b)
}

这样*Integer类型即存在Less()方法,也存在Add()方法,满足LessAdder()接口。而另一方面,根据

func (a *Integer) Add(b Integer)

却无法生成

func (a Integer) Add(b Integer){
  (&a).Add(b)
}

生成函数不能改变外部参数,与用户预期不符。

对象赋值给接口:因而含有语义方法的接口,只能引用赋值。只含值语义方法的接口随意。

接口之间赋值:并不要求两个接口等价,只要包含被赋值接口的所有声明方法即可。

接口查询

由于if语句带有赋值,接口查询的代码要优雅得多。

var a X = 1
if b,ok := a.(Integer); ok{}//注意是接口查询,a只能是接口实例,而不能是结构体的实例。

用switch询问类型:(类型查询)

var v1 interface{} = ...
switch v := v1.(type){
  case int:
  case string:
}

是的,利用反射也可以进行类型查询,详情可参阅reflect.TypeOf()方法的相关文档。

接口组合

go语言的接口即可以写方法,也可以写其它接口。

type ReadWriter interface{
    Reader //Reader接口
    Writer //Writer接口
}

Any类型

空接口可以接受任意对象的实例:

var v1 interface{} = 1
var v2 interface{} = "abc"
var v3 interface{} = &v2

函数可以接受任意对象实例时,也可以声明为interface{}

func Printf(fmt string,args ...interface{})
func Println(args ...interface{})

你可能感兴趣的:(许世伟的Go语言基础 第三章总结)