Golang编程基础第二篇——Golang的面向对象

施飞驰
2023-12-01

Golang作为一种“更好的C语言“,提供了面向对象编程思想的支持。

这一篇是上一篇的补充,主要阐述了go语言面向对象的一些特性,值传递和指针传递在go语言的运用,并补充了一些golang的数据类型

目录

一,Golang面向对象和类型系统

二,Golang的this指针

三,golang的值语义和引用语义

四,结构体


一,Golang面向对象和类型系统

在go中你可以为任何类型添加相应的方法:

//为类型添加方法
type Integer int

//面向对象操作,对象是Integer这个类型的a值
func (a Integer) Less(b Integer) bool {
    return a < b
}

//面向对象调用
func main() {
    var a Integer = 1
    if a.Less(2) {
        fmt.println(a, " Less 2")
    }
}

同时,我们也可以像之前一样面向过程

type Integer int

func Integer_less(a Integer, b Integer) bool {
    return a < b
}

func main() {
    var a Integer = 1
    if Integer_less(a, 2) {
        fmt.Println(a, " less 2")
    }
}

所以能清楚的看出来两者的区别 有助于我们读懂并做好代码 避免有的时候自己调用自己

二,Golang的this指针

首先我们要知道什么是this指针

在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。

在其他语言中比如C#和java,都遵循着C++的惯例,他们的成员方法都有着隐藏的this指针,而python的成员方法中有self参数和this指针作用相同。

在go中没有隐藏的this指针

这句话的含义是:方法施加的目标(即对象),没有被隐藏起来;方法施加的目标(即对象)不需要是指针,也不用非得是this。这里可能有点绕,需要对值传递和引用传递有一定了解,上节我们知道go和C语言一样是基于值传递,要想改变该变量的指针必须传递指针,所以go只有在你需要修改对象的时候,才必须使用指针。比如下面的两个例子:

//指针传递
func (a *Integer) Add(b Integer) {
    *a += b
}

//值传递
func (a Integer) Add(b Integer) {
    a += b
}

//验证
func main() {
    var a Integer = 1
    a.Add(2)
    //指针传递结果为3
    //值传递结果为1
    fmt.Println("a = ", a)
}

三,golang的值语义和引用语义

值语义:

变量赋值后,两个变量拥有的存储空间是独立的,相互之间不影响

引用语义:

变量引用赋值后,两个变量只有一份的存储空间,相互之间可以理解为是别名,操作任意一个变量,就可以认为是操作另外一个变量,效果完全一样

b = a    //值类型
b.Modify()    //引用类型

如果b的修改不影响a的值,那么此类型属于值类型

如果会影响a的值,那么此类型为引用类型

我们可以把go语言所有类型看成是值类型,从这个角度再深入看几个看起来像引用类型的golang类型,他们都是通过指针传递值,所以对于两个指向同一块数据的a或者b进行底层数据的修改来说,两者是互相影响的,比如a[0]=1, 这个是相当于作用于底层市局data

但是若是直接修改a或者b,比如a=[]int{},那么就相当于a对应的struct的值变了,里面的指针p变了之后,就相当于指向了另外一个data。这个时候a和b之间的操作就没有关系了

1. 数组切片

数组切片是指向数组的一个区间

我们复习一下数组切片长这样:

var slice1 []type = make([]type, len)    //声明切片长度和类型的数组切片

也可以简写为

slice1 := make([]type, len)    

数组切片本质是一个区间,你可以大致理解为这样一个结构:

type slice struct {
    first *T
    len int
    cap int
}

因为数组切片内部是指向数组的指针,所以可以改变指向数组元素,其类型本身仍是值语义。

2. map

提供键值查询能力,和我们常见的数据结构相同

/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

/* 你可以讲map[k]v表示为:*/
type Map_k_v struct {
    //...
}

type Map[k]v struct {
    impl *Map_k_v
}

3.channel

执行体(goroutine)间的通信设施,和map类似,本质上是一个指针

ch := make(chan int)

4. 接口

对一组满足某个契约的类型的抽象

//内部维持两个指针
type Interface struct {
    data *void
    itab *Itab
}

 

四,结构体

go的结构体(struct)放弃了大量包括继承在内的面向对象属性,只保留了组合这个最基础的属性。go语言中结构体的使用方式和C语言相同:

//定义结构
type Rect struct {
    x, y float64
    width, height float64
}

//使用
func (r *Rect) Area() float64 {
    return r.width * r.height
}

结构初始化

在go中未显示初始化的变量会被初始化成该类型的零值,而且没有构造函数的概念,对象的创建由写在外面独立的全局的构造函数来完成:

func NewRect (x, y, width, height float64) *Rect {
    return &Rect(x, y, width, height)
}

Struct 类似于 java 中的类,可以在 struct 中定义成员变量。
要访问成员变量,可以有两种方式:
 1.通过 struct 变量.成员 变量来访问。
2.通过 struct 指针.成员 变量来访问。
不需要通过 getter, setter 来设置访问权限。

 

参考资料:Go语言编程

 类似资料: