原计划这篇是写函数的,翻来覆去的研究函数,也没找到什么感悟,于是就写struct吧。这可是个好家伙阿,一个非玩具的C系统中,绝对是struct的天下,可Go更是青出于蓝胜于蓝。
struct在Go中基本总是和type一起出现,Go的type关键字相似于C中的typedef,给一个变量定义个别名。
先欣赏一段struct的代码:
package main import "fmt" /** * 定义Person类 */ type Person struct { name string age int } /** * 为Person类定义方法 */ func (this *Person) SetName(name string) { this.name = name } func (this *Person) GetName() string { return this.name } func (this *Person) SetAge(age int) { this.age = age } func (this *Person) GetAge() int { return this.age } /** * 定义Girl类, 继承于Person */ type Girl struct { Person gender string } func (this *Girl) SetGender(gender string) { this.gender = gender } func (this *Girl) GetGender() string { return this.gender } func main() { p1 := new(Person) p1.SetName("yixiao") p1.SetAge(25) fmt.Printf("Name: %s, Age: %d\n", p1.GetName(), p1.GetAge()) var p2 Person p2.SetName("wxw") p2.SetAge(23) fmt.Printf("Name: %s, Age: %d\n", p2.GetName(), p2.GetAge()) var g Girl g.SetName("lili") g.SetAge(12) g.SetGender("girl") fmt.Printf("Name: %s, Age: %d, Gender: %s\n", g.GetName(), g.GetAge(), g.GetGender()) }
我相信java和C++程序员看到这段代码绝对有一种似曾相识的感觉。封装的数据之上还能提供操作的方法,这就是最基本的面向对象。虽然Go支持一定的面向对象编程,但我们必须得清楚它不是一门OO的语言,仅仅是一门命令式的语言,和C一样。上面代码的mian函数中使用了两种定义Person对象的方法,第一个其实是指针,第二个才是变量,但两种方式都可以用同一种途径来访问其方法,这是Go语言所允许的,如果你是一个C程序员,你可能会非常的惊讶。
上面的代码中也有继承的关系,这都是面向对象编程的基本技术,可我个人还是趋向于尽量避免使用继承,能不用就不用,所有Go支持继承并没有让我为此而兴奋,不过语言级支持为封装的数据类提供方法倒是非常不错的,这就满足很大一部分用C++的类写着C程序的人。因为他们只要简单的数据和方法的封装,不要多态,更不要泛型等。
(纠正:这里准备的说不应该是继承,应该是组合,类型的组合,虽然效果相似于继承。我记得C++程序员就经常争论究竟是用继承还是用组合。)
一个合格的C++程序员绝对不是用C++写着C程序,他们需要熟悉各种奇迹淫巧,需要对C++类的内存分布了如指掌。一个再复杂的类,你只要给他一支笔和一张纸,他就能给你画出各种成员变量,各种方法,虚函数,纯虚函数的内存分布,并且还能清楚的阐述虚函数表的性能等问题。时至今日,我早已经将虚函数,纯虚函数,甚至虚函数表等东东忘得一干二尽了。这些东西根本不是用来帮助你写出优雅的程序,而是阻碍着你,让你一辈子都无法洞悉小的优雅。
面向对象的精髓在于抽象,万物被过度抽象的结果就是迷失自我。
有疑问加站长微信联系(非本文作者)