Golang核心编程(5)-面向对象之类型系统

版权声明: https://blog.csdn.net/pbrlovejava/article/details/83959840


更多关于Golang核心编程知识的文章请看:Golang核心编程(0)-目录页


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

一、什么是类型系统

1.1、Go语言的类型系统

顾名思义,类型系统是指一个语言的类型体系结构。一个典型的类型系统通常包含如下基本内容:

  • 基础类型,如 byte 、 int 、 bool 、 float 等;
  • 基础类型,如 byte 、 int 、 bool 、 float 等;
  • 复合类型,如数组、结构体、指针等;
  • 可以指向任意对象的类型( Any 类型);
  • 值语义和引用语义;
  • 面向对象,即所有具备面向对象特征(比如成员方法)的类型;
  • 接口。

1.2、Java语言的类型系统

类型系统描述的是这些内容在一个语言中如何被关联。因为Java语言自诞生以来被称为最纯正的面向对象语言,所以我们就先以Java语言为例讲一讲类型系统。

在Java语言中,存在两套完全独立的类型系统:一套是值类型系统,主要是基本类型,如 byte 、
int 、 boolean 、 char 、 double 等,这些类型基于值语义;一套是以 Object 类型为根的对象类型系统,这些类型可以定义成员变量和成员方法,可以有虚函数,基于引用语义,只允许在堆上创建(通过使用关键字 new )。Java语言中的 Any 类型就是整个对象类型系统的根—— java.lang.Object类型,只有对象类型系统中的实例才可以被 Any 类型引用。

二、为类型添加方法

Go语言中的大多数类型都是值语义,并且都可以包含对应的操作方法。在需要
的时候,你可以给任何类型(包括内置类型)“增加”新方法。而在实现某个接口时,无需从该接口继承(事实上,Go语言根本就不支持面向对象思想中的继承语法),只需要实现该接口要求的所有方法即可
。任何类型都可以被 Any 类型引用。 Any 类型就是空接口,即 interface{} 。

2.1、为基本类型添加方法

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

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

在这个例子中,我们定义了一个新类型 Integer ,它和 int 没有本质不同,只是它为内置的int 类型增加了个新方法 Less() 。这样实现了 Integer 后,就可以让整型像一个普通的类一样使用:

func main() {
var a Integer = 1
if a.Less(2) {
	fmt.Println(a, "Less 2")
}
}

2.2、传递指针参数和值参数的区别

Go语言中的面向对象最为直观,也无需支付额外的成本。如果要求对象必须以指针传递,这有时会是个额外成本,因为对象有时很小(比如4字节),用指针传递并不划算。

只有在你需要修改对象的时候,才必须用指针。它不是Go语言的约束,而是一种自然约束。

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

这里为 Integer 类型增加了 Add() 方法。由于 Add() 方法需要修改对象的值,所以需要用指针引用。 调用如下:

func main() {
   var a Integer = 1
   a.Add(2)
   fmt.Println("a =", a)
}

运行该程序,得到的结果是: a=3 。如果你实现成员方法时传入的不是指针而是值(即传入Integer ,而非 *Integer ),如下所示:

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

那么运行程序得到的结果是 a=1 ,也就是维持原来的值。

究其原因,是因为Go语言和C语言一样,类型都是基于值传递的。要想修改变量的值,只能传递指针。

三、结构体

Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性。

组合甚至不能算面向对象特性,因为在C语言这样的过程式编程语言中,也有结构体,也有组合。组合只是形成复合类型的基础。

3.1、结构体的定义

type Rect struct {
	x, y float64
	width, height float64
}

3.2、结构体的初始化

	rect1 := new(Rect)
	rect2 := &Rect{}
	rect3 := &Rect{0, 0, 100, 200}
	rect4 := &Rect{width: 100, height: 200}

在Go语言中,未进行显式初始化的变量都会被初始化为该类型的零值,例如 bool 类型的零值为 false , int 类型的零值为0, string 类型的零值为空字符串。

在Go语言中没有构造函数的概念,对象的创建通常交由一个全局的创建函数来完成,以NewXXX 来命名,表示“构造函数”:

func NewRect(x, y, width, height float64) *Rect {
	return &Rect{x, y, width, height}
}

3.3、可见性

Go语言对关键字的增加非常吝啬,其中没有 private 、 protected 、 public 这样的关键
字。要使某个符号对其他包(package)可见(即可以访问),需要将该符号定义为以大写字母开头,如:

type Rect struct {
	X, Y float64
	Width, Height float64
}

这样, Rect 类型的成员变量就全部被导出了,可以被所有其他引用了 Rect 所在包的代码访问到。

猜你喜欢

转载自blog.csdn.net/pbrlovejava/article/details/83959840