类型系统
类型系统是指一个语言的类型体系结构。一个典型的类型系统通常包含以下内容:
- 基础类型:byte int bool ...
- 复合类型:数组 结构体 指针 ...
- 可以指向任意对象的类型(Any类型)
- 值语义和引用语义
- 面向对象的特征 如成员方法
- 接口
类型系统描述的是这些内容在一个语言中如何被关联。
以java举例,在Java中存在两套完全独立的类型系统:一套是值类型系统,主要是基本数据类型(int byte char 等 ),这些类型是值语义的。另一套则是以Object为根的对象类型,这些类型可以定义成员变量和成员方法。java中的Any类型就是Object,值类型想要被Object引用需要装箱(int->Integer)。
相比之下Go语言的大多数类型都是值语义,并且都可以包含对应的操作方法。在需要的时候可以给任何类型添加新方法。而在实现某个接口时,无需从该接口继续(Go不支持继承),只要实现该接口要求的所有方法即可。GO语言的Any类型就是空接口interface(),可以引用任何类型。
为类型添加方法
例1:
package main
import "fmt"
type Integer int
func (a Integer) Less(b Integer) bool {
return a<b
}
func main() {
var a Integer =1
if a.Less(2){
fmt.Println(a,"less 2")
}
}
运行结果:
1 less 2
Process finished with exit code 0
例1 定义了一个新类型Integer,我们为其新增了一个Less方法。
例2:
package main
import "fmt"
type Integer int
func (a *Integer) Add(b Integer) {
*a += b
}
func main() {
var a Integer =1
a.Add(2)
fmt.Println(a)
}
Go语言中的面向对象最为直观,如果要求对象必须以指针传递,这有时会是个额外成本,有时对象很小,用指针传递并不划算。
只有在你需要修改对象的时候,才必须使用指针,比如例2
如果你写成这样
func (a *nteger) Add(b Integer) {
a += b
}
那么你得打的值仍然会是1,而不是3。因为go语言类型都是属于值传递,要想修改变量的值,只能传递指针。
值语义和引用语义
值语义和引用语义的差别在于赋值
b = a
b.Modify()
如果b的修改不会影响a,属于值类型,如果影响属于引用类型。
Go语言中大多数属于值类型,包括:
- 基本类型 int bool 等
- 复合类型 array 结构体struct 指针
Go语言中有4个类型比较特别,看起来像引用类型
- 数组切片:指向数组的一个区间
- map:极其常见的数据类型
- channel:执行体间的通信设施
- 接口:对一组满足某个契约的类型的抽象
结构体
Go 语言的结构体(struct)和其他语言的类(class)有同等地位,但Go放弃了包括继承在内的大量的面向对象的特性,只保留了组合这个最基础的特性。
定义一个矩形类型,再定义Area成员方法来计算面积
type Rect struct {
x, y float64
width, hight float64
}
func (rect *Rect)Area() float64 {
return rect.hight*rect.width
}
初始化
定义好了Rect,可以有以下几种方式初始化:
rect1 := new(Rect)
rect2 :=&Rect{0,0,100,100}
rect3 :=&Rect{width:100,hight:100}
rect4 :=&Rect{}
Go语言没有构函数,使用一个全局的创建函数new来创建
匿名组合
确切的说,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类,该类从Base类“继承”并改写了Bar()
可见性
Go语言对关键字的增加非常的吝啬,其中没有private、protected、public这样的关键字,要使某个符号对其他包可见,需要定义此符号定义为大写字母
接口
接口在Go语言有着至高重要的地位,接口是Go语言整个类型系统的基石,让Go语言在基础编程哲学的探索上达到前所未有的高度。
非侵入式接口
在Go语言中,一个类只需要实现了接口所有的函数,我们就说这个类实现了该接口,甚至可以不知道接口的存在,例如以下File类并没有继承IFile IRead IWrite,但是实现了这些接口,所以就可以进行赋值。
type IFile interface{
Read (buf []byte) (n int,err error)
Write(buf []byte)(n int,err error)
Seek(off int64,whene int)(pos int64,err error)
Close(err error)
}
type IRead interface{
Read (buf []byte) (n int,err error)
}
type IWrite interface{
Write (buf []byte) (n int,err error)
}
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,whene int)(pos int64,err error){}
func (f *File) Close(err error){}
//赋值
var file1 IFile = new(File)
var file2 IRead = new(File)
var file3 IWrite = new(File)
接口赋值
接口赋值在Go语言中有两种情况:
将对象实例赋值给接口
将一个接口赋值给另一个接口
将某种类型的对象赋值给接口
type Integer int
func (a Integer) Less (b Integer)bool{
return a<b
}
func (a *Integer) Add (b Integer)bool{
*a +=b
}
//定义接口LessAdder
type LessAdder interface{
Less (b Integer)bool
Add (b Integer)
}
//将对象赋值给接口
var a Integer = 1
var b LessAdder =&a (1)
var b LessAdder =a (2)
//其中(1)是正确的赋值是(1)