类型系统
GO中大多数类型都是值语义的,并且都可以包含对应的操作方法,而且可以在需要时给类型添加新方法。
在实现某个接口时,无需从该接口继承(事实上GO根本就不支持面向对象中的集成语法),只需实现该接口所要求的所有方法即可。
任何类型都可以被Any类型引用。Any类型就是空接口,即interface{}。
为类型添加方法
可以给任意类型添加方法
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
var a Integer = 1
if a.Less(2) {
fmt.Println(a, "Less 2")
}
“在Go语言中没有隐藏的this指针”这句话的含义是:
方法施加的目标(也就是“对象”)显式传递,没有被隐藏起来;
方法施加的目标(也就是“对象”)不需要非得是指针,也不用非得叫this。
值语义和引用语义
二者差别在于:赋值b = a
b.Modify()
b的修改不会影响a,则是值语义,否则为引用语义
b = &a
b.Modify()
Go语言中的大多数类型都基于值语义,包括:
基本类型,如byte、int、bool、float32、float64和string等;
复合类型,如数组(array)、结构体(struct)和指针(pointer)等。
Go语言中有4个类型比较特别,看起来像引用类型,如下所示:
数组切片:指向数组(array)的一个区间。
map:极其常见的数据结构,提供键值查询能力。
channel:执行体(goroutine)间的通信设施。
接口(interface):对一组满足某个契约的类型的抽象
数组切片:指向数组(array)的一个区间。
map:极其常见的数据结构,提供键值查询能力。
channel:执行体(goroutine)间的通信设施。
接口(interface):对一组满足某个契约的类型的抽象
channel和map类似,本质上是一个指针
结构体
Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合
(composition)这个最基础的特性。
type Rect struct {
x, y float64
width, height float64
}
//定义方法
func (r *Rect) Area() float64 {
return r.width * r.height
}
看上去很像C吧,事实也如此,的使用方式与C语言并没有明显不同
初始化
rect1 := new(Rect)
rect2 := &Rect{}
rect3 := &Rect{0, 0, 100, 200}
rect4 := &Rect{width: 100, height: 200}
未进行显式初始化的变量都会被初始化为该类型的零值:bool ->false int->0 string ->空字符串
在Go语言中没有构造函数的概念,对象的创建通常交由一个全局的创建函数来完成,以
NewXXX来命名,表示“构造函数”:
NewXXX来命名,表示“构造函数”:
func NewRect(x, y, width, height float64) *Rect {
return &Rect{x, y, width, height}
}
匿名组合
确切地说,Go语言也提供了继承,但是采用了组合的文法,所以我们将其称为匿名组合:
type Base struct {
Name string
}
func (base *Base) Foo() { ... }
func (base *Base) Bar() { ... }
type Foo struct {
Base
...
}
func (foo *Foo) Bar() {
foo.Base.Bar()
...
}
以上,定义了Base类,实现了Foo和Bar方法, 定义Foo类,继承并改写了Bar,没有改下Foo也就被继承了
在Go语言中,你还可以以指针方式从一个类型“派生”:
type Foo struct {
*Base
...
}
关注一下接口组合中的名字冲突问题
type X struct {
Name string
}
type Y struct {
X
Name string
}
如上例,Y类型中有有成员Name,其匿名组合X中也有同名的Name,但所有Y类型访问成员Name都只能访问到外层的,X类中的Name被隐藏了
再看:
type Logger struct {
Level int
}
type Y struct {
*Logger
Name string
*log.Logger
}
如上就不行了,匿名组合,可以认为是用其类型名称(去掉包名部分)作为成员变量的名字,这里就会有两个同名的 Logger。那是不可以