golang中的类型系统
序: 在Java语言中,存在两套完全独立的类型系统:一套是值类型系统,主要是基本类型,如byte int boolean char double等,这些类型基于值语义;一套是以object类型为根的对象类型系统,这些类型可以定义成员变量和成员方法,可以有虚函数,基于引用语义,只允许在堆上创建(通过使用关键字new)。Java语言中的Any类型就是整个对象系统的根――java.lang.Object类型,只有对象类型系统中的实例才可以被Any类型引用。值类型想要被Any类型引用,需要装箱(boxing)过程,比如int类型需要装箱成为Integer类型。另外,只有对象类型系统中的类型才可以实现接口,具体方法是让该类型从要实现的接口继承。 相比之下,Go语言中的大多数类型都是值语义,并且都可以包含对应的操作方法。在需要的时候,你可以给任何类型(包括内置类型)"增加"新方法。而在实现某个接口时,无需从该接口集成(事实上,GO语言根本就不支持面向对象思想中的继承语法),只需要实现该接口要求的所有方法即可。任何类型都可以被Any类型引用。Any类型就是空接口,即interface()。 为类型添加方法: 在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") } } 值语义和引用语义: 值语义和引用语义的差别在于赋值,比如下面的例子: b = a b.Modify() 如果b的修改不会影响a的值,那么此类型属于值类型。如果会影响a的值,那么此类型是引用类型。 GO语言中大多数类型都基于值语义,包括: 基本类型,如byte int bool float32 float64 和 string 等 复合类型,如数组(array) 结构体(struct) 和指针(pointer) 等 GO语言中类型的值语义表现的非常彻底。之所以这么说,是因为数组。 GO语言中的数组和基本类型没有区别,是很纯粹的值类型,例如: var a = [3]int{1,2,3} var b = a b[1]++ fmt.Println(a,b) 该程序的运行结果如下: [1 2 3] [1 3 3] 这表明b=a赋值语句是数组内容的完整复制。要想表达引用,需要用指针: var a = [3]int{1,3} var b = &a b[1]++ fmt.Println(a,*b) 该程序的运行结果如下: [1 3 3] [1 3 3] 这表明b=&a赋值语句是数组内容的引用。变量b的类型不是[3]int,而是*[3]int类型。 GO语言中4个类型比较特别,看起来像引用类型,如下所示。 数组切片:指向数组(array)的一个区间。 map:极其常见的数据结构,提供键值查询能力。 channel:执行体(goroutine)间的通信设施。 接口(interface):对一组满足某个契约的类型的抽象。 但是这并不影响我们将GO语言类型看做值语义。下面我们来看看这4个类型。 数组切片本质上是一个区间,你可以大致将[]T表示为: type slice struct { first *T len int cap int } 因为数组切片是指向数组的指针,所以可以改变所指向的数组元素并不奇怪。数组切片类型本身的赋值仍然是值语义。 结构体: GO语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括集成在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性。 上面我们说到,所有的Go语言类型(指针类型除外)都可以有自己的方法。在这个背景下,Go语言的结构体只是很普通的复合类型,平淡无奇。例如,我们要定义一个矩形类型: type Rect struct { x,y float64 width,height float64 } 然后我们定义成员方法Area()来计算矩形的面积: func (r *Rect) Area() float64 { return r.width * r.height } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |