go中的结构体–struct
go中没有面向对象语言中类的概念,go中的struct结构体实现了类似于类的功能,包括类似于成员函数,成员变量等功能
1.go中结构体的定义
1.1 值类型
type T struct {
a int
}
// 通过以下方式,定义了一个T类型的t变量,为值类型
var t T
1.2 引用类型
type T struct {
a int
}
// 通过以下方式,定义了一个&T类型的t变量,为引用类型
// 使用new函数,是为t变量分配了内存空间,在go中,引用类型要使用,必须先分配空间
var t = new(T)
2.go中结构体的内存分布
在go中,结构体在内存中是以连续块的方式存放的
3.结构体中的匿名字段
结构体中,不带变量,只有类型的属性,为结构体中的匿名字段
type T struct {
// 像这种只有类型,没有对应变量的,被称为结构体中的匿名字段
int
}
3.1 匿名字段的定义和使用
- 匿名字段为非结构体类型,可以直接通过t.int这样的方式赋值和使用该匿名字段,因为是根据类型直接使用的,所以一个结构体只能有一个该类型的匿名字段
- 匿名字段为结构体类型,可以通过outer.a这种方式直接访问到inner中的属性和方法
type Inner1 struct {
a int
b int
}
type Outer struct {
c int
int
Inner1
}
var o Outer
o.c = 100
// 可以直接通过以下方式使用Outer中的int匿名字段
o.int = 1000
// 可以通过以下方式访问Inner中的属性
o.a = 100
3.2 命名冲突问题
type Inner1 struct {
a int
b int
}
type Inner2 struct {
a int
c int
}
type Outer struct {
b int
Inner1
Inner2
}
var o Outer
1.上述例子中,当Outer和Inner1中有相同的属性b,此时o.b为外层Outer的b属性;即当外层和内层发生冲突时,优先选择外层
2.上述例子中,当Inner1和Inner2中有相同的属性a,且Outer中没有属性a,此时o.a这种方式使用会报错,因为无法知道要定位到具体哪个Inner中
4.方法
go中没有类似于java中的成员变量和成员方法,可以通过接受者的方式来定义该结构体的对应方法
type T struct {
}
func (t *T) test() {
}
通过以上方式,通过接收者来定义该结构体的对应方法
4.1 该结构体和其对应的方法必须在同一个包内
对于go中自定义的类型,是不能在其他包内直接定义其方法的,可以使用类型别名或者匿名字段的方法
package main
// 这种方式是错误的,方法和结构体必须在同一个包内
func (t time.Time) test() {
}
// 使用类型别名
type T time.Time
func (t T) test1() {
t1 := time.Time(t)
// 使用类型别名的方式后,需强制类型转换才能使用原来类型的方法
t1.Minute()
}
// 使用匿名字段
type T1 struct{
time.Time
}
func (t *T1) test2() {
// 使用匿名字段后,可直接通过下列方式使用原来类型的方法
t.Minute()
}
4.2 定义方法时,接收者可为值类型或者引用类型
1.接收者为值类型时,不会改变原来的值
type T struct{
a int
}
func (t T) NotChange() {
t.a = 100
}
var t T
t.a = 10
t.NotChange() // 执行该函数后,t.a仍然为10,不会改变原来的值
2.接收者为引用类型时,会改变原来的值
type T struct{
a int
}
func (t *T) Change() {
t.a = 100
}
var t T
t.a = 10
t.Change() // 执行该函数后,t.a的值会更改为100,会改变原来的值
3.在go中,无论是值类型还是引用类型,在方法或函数中,都是采用值传递的。对于引用类型来说,传递的是地址的拷贝,因此引用类型会改变指向的地址的内容
4.3 可通过匿名字段的方式实现类似于java中的继承效果
type Inner1 struct{
}
type Inner2 struct{
}
func (i Inner1) call() {
fmt.Println("calling")
}
func (i Inner2) take() {
fmt.Println("taking")
}
type Outer struct {
Inner1
Inner2
}
var o Outer
// 通过以下方式可以达到类似于继承的效果
o.call()
o.take()