主题:【原创】介绍一下Go语言(1)之前的话 -- zllwy
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的要灵活。你可以比较容易地对你的代码进行改进,而不需要担心要对已有代码做大手术。
- 相关回复 上下关系8
🙂10年以前有过实现 1 美人他爹 字462 2011-01-27 21:28:38
🙂Dynamo 1 zllwy 字145 2011-02-01 14:37:47
🙂Binary Translate 美人他爹 字12 2011-02-01 15:41:16
🙂【原创】介绍一下Go语言(3)Type system
🙂关于这个type,我还是有些疑问 铁手 字365 2011-01-25 15:19:40
🙂试着回答一下 1 zllwy 字611 2011-01-26 17:47:11
🙂Python很适合初学者 1 大龙猫 字338 2011-01-24 07:12:26
🙂是马甲么? 喵咪呜 字25 2011-01-24 17:50:08