美文网首页
Go语言学习笔记2:面向对象编程

Go语言学习笔记2:面向对象编程

作者: 本人是个帅哥_ | 来源:发表于2020-07-13 14:46 被阅读0次

    前言

    相比于传统的Java,C#和C++语言相比,Go语言对于面向对象的支持非常的简洁而优雅。简洁之处在于,Go语言并没有沿袭传统面向对象的诸多的概念,如继承(采用组合进行替换)、虚函数、构造函数和析构函数、隐藏的this指针等。优雅之处在于,Go语言对面向对象编程的支持是语言类型系统中的天然组成部分。整个类型系统通过接口串联,浑然一体。

    类型系统

    类型系统是指一个语言的类型体系结构,一个典型的类型系统包括如下的基本内容:基础类型(byte、int、bool、float等),复合类型(数组、结构体/类、指针等),指向任意对象的类型(Object/Any等),值语义和引用语义,面向对象的特征、接口等。
    Java语言将类型系统分成两类,基本类型系统(byte、int、long、double、boolean等8种)和引用类型(继承至Object类)。相比于Java语言,Go语言中的大多数类型都是值语义,并且都可以包含对应的操作方法。在需要的时候,你可以给任何类型(包括内置类型)“增加”新方法。而在实现某个接口时,无需从该接口继承(Go不支持继承),只需要实现该接口要求的所有方法即可。任何类型都可以被Any类型引用。Any类型就是空接口,即interface{}。

    为类型系统添加新方法

    在Go语言中,你可以给任意类型(包括内置类型,但是不包括指针类型)添加相应的方法,如下所示:


    1.png

    Go语言的面向对象最为直观,无需支付额外的成本。如果要求对象必须以指针传递,这有时会是个额外的成本,因为对象有时候很小(如几个字节),用指针传递并不划算。只有你需要进行修改的时候,才需要用指针,如Integer类型的加法运算 func (a *Integer )Add (b Integer){ return *a = * a + b}。注意:Go语言和C语言一样,类型都是基于值传递的。要想修改变量的值,只能传递指针。

    值语义和引用语义

    值类型对象传递时候会完整的拷贝一份数据,引用类型对象则不会。Go语言中大多数类型都是值语义,包括基本类型(byte、int、bool等)和复合类型(数组、结构体、指针)等。


    2.png

    结构体

    Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但是Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合这个最基础的特性。组合甚至不能算是面向对象的特性,因为在C语言中这样的过程编程语言中,也有结构体和组合。组合只是形成复合类型的基础。

    初始化

    定义一个Rect结构体之后,应该如何进行初始化呢,如下所示:


    3.png

    在Go语言中,未进行显示初始化的变量都会被初始化为该类型的零值,例如bool类型的零值为false,int类型的零值为0,string类型的零值为空字符串。在Go语言中没有构造函数的概念,对象的创建通常交给一个全局的创建函数来完成,以NewXX来命名,表示“构造函数”

    匿名组合

    准确的来说,Go语言也提供了继承,但是采用的是组合的方式,所以我们将其称为匿名组合。

    可见性

    Go语言的关键字很少,其中没有类似Java语言中的private、public、、protected这样的关键字。要使某个符号对其他包(package)可见,需要将该符号定义为大写开头,结构体的成员方法的可达性遵循同样的规则。

    接口

    Go语言的主要设计者之一Rob Pike曾说过,如果选择一个Go语言的特性移植到其他语言中,他会选择接口,可以说,接口是Go语言整个类型系统的基石。

    其他语言的接口

    Go语言的接口并不是其他语言(C++、Java、C#等)中所提供的概念。在Go语言出现之前,接口主要作为不同组件之间的契约存在。对契约的实现是强制的,你必须申明你的确实现了该接口。在Go语言中,一个类只需要实现接口要求的所有的函数,我们就说这个类实现了该接口,尽管File类并没有继承IFile接口,甚至可以不用知道这些接口的存在,但是File类实现了这些接口,可以进行赋值,例如:


    4.png

    在Go语言中,类的继承树并没有任何的意义,你只需要知道这个类实现了那些方法,每个方法是啥含义就足够了。其次,实现类的时候,只需要关系自己应该提供那些方法,不用纠结接口需要拆分得多细才合理,接口由适用方按需求定义,而不用事前规划。还有就是为了实现一个接口而导入一个包,因为多引用一个外部的包,就意味着更多的耦合,接口由使用方按照自己需求来定义,使用方无需关心是否有其他模块定义过类似的接口。

    接口赋值

    接口赋值在Go语言中分为如下两种情况:

    • 将对象实例赋值给接口;
    • 将一个接口赋值给另一个接口;
      先讨论将某种类型的对象实例赋值给接口,这要求该对象实例实现了接口所有方法,例如之前的Integer类型。如下:
      type Integer int
      func (a Integer) Less(b Integer) bool {
      return a < b
      }
      func (a *Integer) Add(b Integer) {
      *a +=b
      }
      相应的,我们定义接口LessAdder,如下:
      type LessAdder interface {
      Less(b Integer) bool
      Add(b Integer)
      }
      假如我们定义一个Integer类型的对象实例,怎么将其赋值给LessAdder接口呢?
      var a Integer = 1
      var b LessAdder = &a
      下面,我们再来讨论另一种情形:将一个接口赋值给另一个接口。在Go语言中,只要两个接口拥有相同的方法列表(次序不同不要紧),那么他们就是等同的,可以相互赋值。

    Any类型

    由于Go语言中任何对象实例都满足空接口interface{},所以interface{}看起来像是可以指向任何对象的Any类型,如下:
    var v1 interface{} = 1
    var v2 interface{} = "abc"

    相关文章

      网友评论

          本文标题:Go语言学习笔记2:面向对象编程

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