西西河

主题:【原创】介绍一下Go语言(1)之前的话 -- zllwy

共:💬92 🌺231
全看分页树展 · 主题 跟帖
家园 【原创】介绍一下Go语言(3)Type system

Go的一大特点是它的type system。在写这篇之前我发现自己其实对很多概念也一知半解,这里就先把type system的一些概念梳理一下。如果有谬误,希望给我指出。

Go有很多方面和python很像。而python又是一个比较有代表性的语言,我这里就主要用Go和python做比较。

首先是static type和dynamic type。static type简单说就是type checking是在compile time做的,而dynamic type是在runtime做的。Go是statically typed而python是dynamically typed。说一下我对这两者的评价。我是基本倾向于用static type语言的,特别是大型项目。支持dynamic type的人的最主要理由就是实际当中type error是很少的(我的体会是其实很常见,而且很难调试),所以到runtime去检查没什么,但开发要快很多。其实我不是很赞同。因为我觉得特别对于大型系统来说,coding其实不占主要时间,design和debugging更花时间。而且static type语言一般效率要高一些。综合来看,dynamic语言除了用来写script,tool比较好以外,真正重要的项目还是应该用static语言。

然后是weakly typed和strongly typed。strongly typed是指任何使用value的时候都要检查它的type,对不上的话就不行。当然这个可以在runtime做(对dynamic type语言)或者在compile time做(对static type语言)。Go和python都是strongly typed。Javascript就不是。这里对python可能有些容易混淆的地方。python可以写:

onevar = 1

onevar = "1"

这个不说明python是weakly typed。因为赋值给变量其实只是一个绑定,关键还是看在用它的值的时候是不是检查type。

还有一个概念是type safety。你不能说一个语言是type safe还是不safe,你只能说多大程度上是safe的。比如C是某种程度上的safe,还是有很多漏洞。C++强一些。Java,C#更强。所以static type system不一定就意味着很强的type safety。

再来讲polymophism,多态。C++用type hierarchy来实现多态。C++的type system比较复杂,有单继承还有多重继承。Java就简化了一下。Java的Interface提供了一定的灵活性。你不必一定要继承某个类,实现一个interface就可以实现多态了。实际上有人建议尽量使用interface而少用inheritance。这个后面再说。但interface的问题是如果有些第三方的代码你不能改,你就很难把它融入到你的type system里面来。这就出现了duck typing和structural typing。duck typing和structural typing很类似。都是说只要你实现了某些性质,你就可以被称为某个类。有人称为signature based polymorphism。duck typing的代表就是python,很有名的一句话就是:

"When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck."

所以duck typing是看一个value是否存在某组属性来进行type checking的。structural typing也很类似,如果一个类实现了一组确定的接口,它就可以被当作那套接口定义的type。区别在于,duck typing是在runtime检查,而strcutural typing在compile time检查。Go是structurally typed。

再来说一下inheritance和composition。如果你要subclass一个基类,你可以选择用"as-a"还是"has-a"。"as-a"就是继承,说明新的类是基类的一种。"has-a"就是组合,说明新的类拥有基类的能力。目前的主流看法是尽量用"has-a",也就是composition。这里就不展开了。Go提供了一些方便使得composition可以基本取代inheritance。这样Go的type system就非常简单了。

现在可以来说Go的type system了。首先Go里面只有struct,没有class。但你可以在任何type上定义函数,设置在primitive type上定义。比如:

type INT int

func (a INT) printa() {

fmt.Println(a)

}

这里你不能直接在int上定义函数,要先定义自己的type,然后在上面定义函数。然后:

var a INT = 1

a.printa()

你实际上就是在整数类型上定义了一个新的操作。结合struct,你可以给任何一个struct定义函数。基本上,你可以把被定义的struct看做是那个函数的一个参数。这样我们就有类似class的功能了。

如果你又定义了一个指针:

var ap *INT = &a

ap就也有了a的函数。你可以写

ap.printa()

更进一步,你可以组合struct来实现subclassing。比如

type T1 struct {

a int

}

type T2 struct {

T1 // anonymous field

b, c int

}

现在T2有了T1所有的东西,你可以直接写:

var t T2

t.a

t.b

t.c

T2还可以直接调用T1的函数。

再来看Go是怎么定义两个类型的可赋值性的(assignability)。如果你要把一个值赋给一个lhs,Go值看两边的类型是否完全等价。比如:

type T1 struct {

a, b int

}

type T2 struct {

a, b int

}

在C/C++里面,这是两个类,是不能赋值的。但Go把他们当作是一样的。

最后,终于说到interface了。如果你有这么一个interface:

type Api interface {

Foo(a int) int

Bar(b float) float

}

这样只要任何一个type实现了这两个函数,就可以被当作Api来用。这样就实现了polymorphism,而且比用type hierarchy的要灵活。你可以比较容易地对你的代码进行改进,而不需要担心要对已有代码做大手术。

元宝推荐:铁手,
全看分页树展 · 主题 跟帖


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河