首先说一个概念性问题:
- Go 语言仅支持封装,不支持继承和多态;
- GO 语言没有 class ,只有 struct;
Go 语言的结构体(struct)和其他语言的类(class)有同等的地位,但 Go 语言放弃了包括继承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性。
组合甚至不能算面向对象特性,因为在 C 语言这样的过程式编程语言中,也有结构体,也有组合。组合只是形成复合类型的基础。
原来说过,所有的 Go 语言类型(指针类型除外)都可以有自己的方法。在这个背景下,Go语言的结构体只是很普通的复合类型,平淡无奇。例如,我们要定义一个矩形类型:
type Rect struct {
x, y float64
width, height float64
}
然后我们定义成员方法 Area()来 计算矩形的面积:
func (r *Rect) Area() float64 {
return r.width * r.height
}
可以看出, Go 语言中结构体的使用方式与 C 语言并没有明显不同。
初始化
在定义了 Rect 类型后,该如何创建并初始化 Rect 类型的对象实例呢?这可以通过如下几种方法实现:
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}
}
这一切非常自然,开发者也不需要分析在使用了 new 之后到底背后发生了多少事情。在 Go 语言中,一切要发生的事情都直接可以看到。
结构创建在堆上还是桟上?
答:不需要知道。这个是有 Go 的编译器和运行环境决定的,如下面的代码
func NewRect(x, y, width, height float64) *Rect {
return &Rect{x, y, width, height}
}
上方代码,返回的是一个取地址返回的变量,那这里就是在堆上开内存空间,在外部有人在使用这个变量,那么这个变量就要参与垃圾回收,并不是说这个方法运行完毕变量就回收了,而是在外部没有引用之后再进行回收。反之亦然。
文章评论