美文网首页
许世伟的Go语言基础 第三章总结

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

作者: fjxCode | 来源:发表于2018-07-16 20:21 被阅读0次

    第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<b
    }
    func (a *Integer) Add(b Integer)  {
        *a += b
    }
    
    type LessAdder interface {
        Less(b Integer) bool
        Add(b Integer)
    }
    
    func main() {//无返回值不用写void
        var a Integer = 1
        var b LessAdder = &a
        var c LessAdder  = 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语言基础 第三章总结

          本文链接:https://www.haomeiwen.com/subject/qbohpftx.html