go结构体

举报
Rolle 发表于 2023/11/30 17:34:16 2023/11/30
【摘要】 类型定义和类型别名的区别​类型别名与类型定义表面上看只有一个等号的差异,我们通过下面的这段代码来理解它们之间的区别。//类型定义type NewInt int//类型别名type MyInt = intfunc main() { var a NewInt var b MyInt fmt.Printf("type of a:%T\n", a) //type of a:mai...

类型定义和类型别名的区别

类型别名与类型定义表面上看只有一个等号的差异,我们通过下面的这段代码来理解它们之间的区别。

//类型定义
type NewInt int
//类型别名
type MyInt = int
func main() {
    var a NewInt
    var b MyInt
    fmt.Printf("type of a:%T\n", a) //type of a:main.NewInt
    fmt.Printf("type of b:%T\n", b) //type of b:int
}

结果显示a的类型是main.NewInt,表示main包下定义的NewInt类型。b的类型是int。MyInt类型只会在代码中存在,编译完成时并不会有MyInt类型。

构造函数

Go语言的结构体没有构造函数,可以自己实现。 例如,下方的代码就实现了一个person的构造函数。 因为struct是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以该构造函数返回的是结构体指针类型。

func newPerson(name, city string, age int8) *person {
    return &person{
        name: name,
        city: city,
        age:  age,
    }
}

匿名结构体

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为匿名字段。

var apr = struct {
        Name string
        Age  int
    }{
        Name: "zhangsan",
        Age: 13,
    }

go中的结构体内存布局和c结构体布局类似,每个成员的内存分布是连续的,在以下示例中通过反射进行进一步说明:

package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Name  string
	Age   int64
	wight int64
	high  int64
	score int64
}

func main() {
	var stu1 = new(Student)
	fmt.Printf("%p\n", &stu1.Name)
	fmt.Printf("%p\n", &stu1.Age)
	fmt.Printf("%p\n", &stu1.wight)
	fmt.Printf("%p\n", &stu1.high)
	fmt.Printf("%p\n", &stu1.score)
	typ := reflect.TypeOf(Student{})
	fmt.Printf("Struct is %d bytes long\n", typ.Size())
	// We can run through the fields in the structure in order
	n := typ.NumField()
	for i := 0; i < n; i++ {
		field := typ.Field(i)
		fmt.Printf("%s at offset %v, size=%d, align=%d\n",
			field.Name, field.Offset, field.Type.Size(),
			field.Type.Align())
	}
}


// result
0xc000098180
0xc000098190
0xc000098198
0xc0000981a0
0xc0000981a8
Struct is 48 bytes long
Name at offset 0, size=16, align=8
Age at offset 16, size=8, align=8
wight at offset 24, size=8, align=8
high at offset 32, size=8, align=8
score at offset 40, size=8, align=8

可以看到内存地址的偏移总是以8字节偏移(使用的是int64,刚好是8字节),在观察其内存地址,也是连续的,所以go语言中结构体内存布局是连续的。如图:

image.png

因为空结构体是不占用内存的,所以size为0,在内存分配时,size为0会统一返回zerobase的地址,所以空结构体在进行参数传递时,发生值拷贝后地址都是一样的,才造成了这个质疑Go不是值传递的假象。

所以在判断是否存在的时候可以 maptypestruct{}

空结构体在结构体中的前面和中间时,是不占用空间的,但是当空结构体放到结构体中的最后时,会进行特殊填充,struct { } 作为最后一个字段,会被填充对齐到前一个字段的大小,地址偏移对齐规则不变;

  1. 空结构体也是一个结构体,不过他的size为0,所有的空结构体内存分配都是同一个地址,都是zerobase的地址;
  2. 空结构体作为内嵌字段时要注意放置的顺序,当作为最后一个字段时会进行特殊填充,会被填充对齐到前一个字段的大小,地址偏移对齐规则不变;
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。