Go的面向对象
go的面向对象编程和传统的有区别,go只是支持面向对象编程特性,相对简洁,去掉了传统oop的extends,方法重载,构造函数和折构函数,this等
go仍然有面向对象编程的继承,封装,多态特性,只是实现方式同传统面向对象不同
结构体
只有结构体实例化的时候才分配内存
Go语言可以通过多种方式实例化结构体,根据实际需要可以选用不同的写法。
第一种
var ins T // 通过声明来实例化
第二种
ins := new(T) // 通过内置函数new,这里ins的类型是*T属于指针
ins.Name = "张三" // 可以用.给结构体字段赋值,C语言通过指针访问成员变量只能用 ->,这是Go的语法糖
第三种
ins := &T{} // 在Go语言中,对结构体进行&取地址操作时,视为对该类型进行一次 new 的实例化操作
ins := T{} //这里ins类型是T
初始化结构体
ins := 结构体类型名{
字段1: 字段1的值,
字段2: 字段2的值,
…
}
ins := 结构体类型名{
字段1的值,
字段2的值,
…
}
ins := &结构体类型名{
字段1: 字段1的值,
字段2: 字段2的值,
…
}
// 这时的ins就是地址了
匿名结构体
匿名结构体没有名称,无需type关键字可以直接使用
ins := struct {
// 匿名结构体字段定义
字段1 字段类型1
字段2 字段类型2
…
}{
// 字段值初始化
初始化字段1: 字段1的值,
初始化字段2: 字段2的值,
…
}
结构体细节
-
结构体名称是直接指向实际结构体实例内存空间的,并没有指向一个地址这个地址再指向实际内存,所以go中的结构体是值类型的,默认值拷贝
-
结构体所有字段在内存中是连续的
-
结构体之间可以类型转换但是结构体字段要完全一样
-
struct字段上可以写一个tag,该tag可以通过反射机制获取,常见与序列化和反序列化
-
// Cat 结构体字段名大写是为了让别的包能访问到这个字段, // 比如json序列化结构体,如果字段名小写,那么json包不能访问就无法序列化 type Cat struct { Name string `json:"name"` // struct tag Age int `json:"age"` Color string `json:"color"` }
-
方法
- golang的方法是和数据类型绑定的,自定义类型都可以有方法
- 在通过一个变量调用方法时,其调用机制和函数一样
- 不一样的地方是变量调用方法时,该变量本身也会作为一个参数传递到方法 ,这个变量是值类型,那么传递到这个方法时就会进行值拷贝,一般对于结构体我们使用指针类型变量传递,避免了值拷贝,提高效率
func (a *A) Test() {
fmt.Println(a.num)
}
- 如果一个类型实现了String()这个方法,那么fmt.Println默认调用这个变量的String进行输出
和函数的区别:
- 调用方式不一样
- 函数:函数名(实参列表)
- 方法:变量.方法名(实参列表)
- 函数的接收者为值类型就只能传值类型,是指针类型就只能传指针类型
- 方法接收者为值类型,也可以直接用指针类型的变量调用方法,反之亦然
- 需要注意的是,如果方法接受者为值类型,我们用指针类型变量调用,形式上是传入地址,本质依然是值拷贝,简单来说就是方法接收者是什么类型,调用是就是什么拷贝,和调用它的变量的类型无关
工厂模式
golang结构体没有构造函数,通常使用工厂模式来解决这个问题
如果结构体名字首字母小写,我们还想在其他包中创建该结构体实例,就可以使用类似于其他语言中的构造函数来解决
func newCommand(name string, varref *int, comment string) *Command {
return &Command{
Name: name,
Var: varref,
Comment: comment,
}
}
cmd = newCommand(
"version",
&version,
"show version",
)
继承
为了解决代码复用,减少冗余
golang中没有extends,实现继承的效果是通过嵌入匿名结构体
type Goods struct {
Name string
Price float64
}
type Book struct {
Goods
Author string
}
type TV struct {
*Goods
}
var b Book
- 结构体可以使用嵌套匿名结构体所有字段和方法,不管大写还是小写
- 匿名结构体字段访问可以简化
b.Goods.Name—>b.Name(编译器会先看Book中有没有Name字段,如果有直接调用Book的,没有就去看Book中嵌入的匿名结构体) - 当结构体和它嵌入的匿名结构体有相同的字段,访问时遵循
就近原则,如果希望访问匿名结构体中的,可以通过匿名结构体名来区分 - 如果嵌入多个匿名结构体,其中有相同的字段或方法,在访问时就必须指定匿名结构体名,否则编译报错
- 如果嵌入的是有名结构体,访问其中字段必须带上嵌入结构体名(嵌入有名结构体实现的效果就不是继承了,只是简单组合)
嵌入匿名字段也是允许的
真亲切……