[Go深入语法学习 | 青训营笔记]

41 阅读2分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 4 天。

今天,我主要深入学习并回顾了Go语言的指针与结构体。

一、指针初步

指针(pointer)是C/C++中最为晦涩难懂的理念,它代表着一个指向底部内存空间或其他类似性质的东西的“标记”,往往能够衍生出各式各样晦涩难懂的理念(强制类型转换,多重指针,数组指针与指针数组)。总的来说,指针的难点在于学习者对于操作系统和计算机组成原理的底层概念的不理解。

在Go语言中,同样存在着“指针”的概念。

func swap(a *int, b *int) {
    x := *a;
    *a = *b;
    *b = x;
}
swap(&a, &b)

不难感受到,我们对指针的应用是和C类似的。

指针单独理解其实还好,问题往往在于这些:函数传递中的指针是怎样处理的?指针对于结构体和数组、切片等数据结构是怎样应用的?

二、结构体、类型与方法

我们学到过,我们可以像C中的struct那样进行数据的聚合:

type student struct {
    name string
    age int
    id string
}

为了实现类似于C++/Java中的“方法”,我们可以给某种类型“附加”一些函数,例如:

func (p person) getName() string {
    return p.name
}
func (p *person) addAge() {
    p.age++
}

p.getName()
p.addAge()

Go提供了一些语法糖,使得我们可以不用过分拘泥于细节(例如第5行不需要额外写成(*p).age++,第9行也会自动转换成(&p).addAge())。

指针接收者是可以接收nil的,这使得我们可以省去很多分类讨论。

类型不止可以修饰一个结构体,也可以修饰一个基本类型。打个比方,我想要写一个给数字的String函数,那么我们可以如下所示:

type myint int
func (x myint) String() {
    //TODO
}

var x myint = 5
fmt.println(x.String())

Go没有传统的“继承”(OOP的核心之一)的概念,相反,他更建议“使用对象组合优于类继承”,例如创建两个结构体:

type Employee struct {
    Name string
    ID   string
}
func (e Employee) Description() string {
    return fmt.Sprintf("%s(%s)", e.Name, e.ID)
}
type Manager struct {
    Employee
    Reports []Employee
}
func (m Manager) Dosomething() {
    // TODO
}

在这里,Manager看起来有点类似Employee的之类,但其实不是,这仅仅是一个组合而已,Employee是Manager的一个内嵌字段,它的字段和方法会被提到整体上并进行调用,例如说你可以直接调用m.Description() 方法。