声明:内容来自《Go语言编程》
[TOC]
Go语言对面向对象编程的支持是语言类型系统中的天然组成部分
1 类型系统
类型系统是指一个语言的类型体系结构
1.1 为类型添加方法
type Integer int func (a Integer) Less(b Integer) bool { return a < b }
关于给类型添加方法的时候,类型的参数是传入指针?还是值传递?如下:
func (a *Integer) Add(b Integer) { *a += b } func (a Integer) Add(b Integer) { a += b }
这取决于,你是否需要需要修改对象!若需要修改对象,则需要传入指针。类型都是基于值传递的。要想修改变量的值,只能 传递指针
1.2 结构体
type Rect struct { x, y float64 width, height float64 } func (r *Rect) Area() float64 { return r.width * r.height }
2 初始化
rect1 := new(Rect) rect2 := &Rect{} rect3 := &Rect{0, 0, 100, 200} rect4 := &Rect{width: 100, height: 200}
- 未进行显式初始化的变量都会被初始化为该类型的零值。例如bool类型的零 值为false,int类型的零值为0,string类型的零值为空字符串。
- 在Go语言中没有构造函数的概念,对象的创建通常交由一个全局的创建函数来完成,以 NewXXX来命名,表示“构造函数”:
func NewRect(x, y, width, height float64) *Rect { return &Rect{x, y, width, height} }
3 匿名组合
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() ... }
4 接口
Go语言在编程哲学上是变革派,是因为Go语言的类型系统,更是因为Go语言的接口
“侵入式”的主要表现在于实现类需要明确声明自己实现了某个接口。“非侵入式”只需要实现接口的方法,不需要声明。
type File struct { // ... } func (f *File) Read(buf []byte) (n int, err error) func (f *File) Write(buf []byte) (n int, err error) func (f *File) Seek(off int64, whence int) (pos int64, err error) func (f *File) Close() error type IFile interface { Read(buf []byte) (n int, err error) Write(buf []byte) (n int, err error) Seek(off int64, whence int) (pos int64, err error) Close() error } type IReader interface { Read(buf []byte) (n int, err error) } type IWriter interface { Write(buf []byte) (n int, err error) } type ICloser interface { Close() error } var file1 IFile = new(File) var file2 IReader = new(File) var file3 IWriter = new(File) var file4 ICloser = new(File)
尽管File类并没有从这些接口继承,甚至可以不知道这些接口的存在,但是File类实现了 这些接口,可以进行赋值。
非侵入式接口的好处:
- Go语言的标准库,再也不需要绘制类库的继承树图。
- 实现类的时候,只需要关心自己应该提供哪些方法,不用再纠结接口需要拆得多细才合理。
- 不用为了实现一个接口而导入一个包,因为多引用一个外部的包,就意味着更多的耦合。
在Go语言中,只要两个接口拥 有相同的方法列表(次序不同不要紧),那么它们就是等同的,可以相互赋值。
4.1 接口查询
var file1 Writer = ... if file5, ok := file1.(two.IStream); ok { ... }
这个if语句检查file1接口指向的对象实例是否实现了two.IStream接口,如果实现了,则执 行特定的代码。
4.2 类型查询
var v1 interface{} = ... switch v := v1.(type) { case int: // 现在v的类型是int case string: // 现在v的类型是string ... }
5 Any类型
由于Go语言中任何对象实例都满足空接口interface{},所以interface{}看起来像是可以指向任何对象的Any类型。
var v1 interface{} = 1 // 将int类型赋值给interface{} var v2 interface{} = "abc" // 将string类型赋值给interface{} var v3 interface{} = &v2 // 将*interface{}类型赋值给interface{} var v4 interface{} = struct{ X int }{1} var v5 interface{} = &struct{ X int }{1}