美文网首页
go结构体的初始化及内存布局

go结构体的初始化及内存布局

作者: ag4kd | 来源:发表于2022-01-23 19:01 被阅读0次

初始化方式

方式一:通过 var 声明结构体

在 Go 语言中当一个变量被声明的时候,系统会自动初始化它的默认值,比如 int 被初始化为 0,指针为 nil。

var 声明同样也会为结构体类型的数据分配内存,所以我们才能像上一段代码中那样,在声明了 var s T 之后就能直接给他的字段进行赋值

方式二:使用 new

使用 new 函数给一个新的结构体变量分配内存,它返回指向已分配内存的指针:var t *T = new(T)。

type struct1 struct {
    i1 int
    f1 float32
    str string
}

func main() {
    ms := new(struct1)
    ms.i1 = 10
    ms.f1 = 15.5
    ms.str= "Chris"

    fmt.Printf("The int is: %d\n", ms.i1)
    fmt.Printf("The float is: %f\n", ms.f1)
    fmt.Printf("The string is: %s\n", ms.str)
    fmt.Println(ms)
}

与面向对象语言相同,使用点操作符可以给字段赋值:structname.fieldname = value

同样的,使用点操作符可以获取结构体字段的值:structname.fieldname

方式三:使用字面量

type Person struct {
    name string
    age int
    address string
}

func main() {
    var p1 Person
    p1 = Person{"lisi", 30, "shanghai"}   //方式A
    p2 := Person{address:"beijing", age:25, name:"wangwu"} //方式B
    p3 := Person{address:"NewYork"} //方式C
}

方式A中,值必须以字段在结构体定义时的顺序给出。

方式B是在值前面加上了字段名和冒号,这种方式下值的顺序不必一致,并且某些字段还可以被忽略掉,就像方式C那样。

方式 四

除了上面这三种方式外,还有一种初始化结构体实体更简短和常用的方式,如下:

ms := &Person{"name", 20, "bj"}
ms2 := &Person{name:"zhangsan"}

&Person{a, b, c} 是一种简写,底层仍会调用 new(),这里值的顺序必须按照字段顺序来写,同样它也可以使用在值前面加上字段名和冒号的写法(见上文的方式B,C)。

  • 表达式 new(Type)&Type{}是等价的。

几种初始化方式之间的区别

到目前为止,我们已经了解了三种初始化结构体的方式:

//第一种,在Go语言中,可以直接以 var 的方式声明结构体即可完成实例化(var 声明同样也会为结构体类型的数据分配内存 )
var t T
t.a = 1
t.b = 2

//第二种,使用 new() 实例化
t := new(T)

//第三种,使用字面量初始化
t := T{a, b} // 分配内存,并返回该类型
t := &T{} //简写方式,等效于 new(T),就是对上面那种写法取地址,返回指针
  • 使用 var t T 会给 t 分配内存,并零值化内存,但是这个时候的 t 的类型是 T;
  • 使用 new 关键字时 t := new(T),变量 t 则是一个指向 T 的指针。

从内存布局上来看,我们就能看出这三种初始化方式的区别:

使用var 声明:直接为该变量分配内存。

img

使用 new 初始化:为类型分配内存后,返回该类型的指针。

img

使用取结构体的地址实例化:相当于上面两种方式的简写。

img

下面来看一个具体的例子

package main
import "fmt"

type Person struct {
 name string
 age int
}

func main() {
 var p1 Person // 分配内存,并初始化为 0 值
 p1.name = "zhangsan"
 p1.age = 18
 fmt.Printf("This is %s, %d years old\n", p1.name, p1.age)

 p2 := new(Person) //分配内存,返回指针
 p2.name = "lisi"
 p2.age = 20
 (*p2).age = 23 //这种写法也是合法的
 fmt.Printf("This is %s, %d years old\n", p2.name, p2.age)

 p3 := Person{"wangwu", 25} //分配内存,并初始化为字面值
 fmt.Printf("This is %s, %d years old\n", p3.name, p3.age)
}

输出:

This is zhangsan, 18 years old
This is lisi, 23 years old
This is wangwu, 25 years old

上面例子的第二种情况,虽然 p2 是指针类型,但我们仍然可以像 p2.age = 23 这样赋值,不需要像 C++ 中那样使用 -> 操作符,Go 会自动进行转换。

注意也可以先通过 * 操作符来获取指针所指向的内容,再进行赋值:(*p2).age = 23

疑点解答

  • 为什么new 出来的指针变量,也可以像 var 声明的变量一样来使用结构体字段?

虽然 p2 是指针类型,但我们仍然可以像 p2.age = 23 这样赋值,不需要像 C++ 中那样使用 -> 操作符,Go 会自动进行转换。

结构体的内存布局

Go 语言中,结构体和它所包含的数据在内存中是以连续块的形式存在的。

即使结构体中嵌套有其他的结构体,这在性能上带来了很大的优势。

不像 Java 中的引用类型,一个对象和它里面包含的对象可能会在不同的内存空间中,这点和 Go 语言中的指针很像。

下面的例子清晰地说明了这些情况:

type Rect1 struct {Min, Max Point }
type Rect2 struct {Min, Max *Point }
img

相关文章

  • go结构体的初始化及内存布局

    初始化方式 方式一:通过 var 声明结构体 在 Go 语言中当一个变量被声明的时候,系统会自动初始化它的默认值,...

  • 第03天(复合类型)_结构体的基本使用

    29_结构体普通变量初始化 30_结构体指针变量初始化.go 31_结构体成员的使用:普通变量.go 32_结构体...

  • GO语言学习

    go语言的结构体 声明:type 结构体名 struct{x,y int}初始化:未显示初始化结构体变量的,初始值...

  • 结构体

    结构体有名定义 无名定义 结构体嵌套定义 结构体内存对齐 结构体成员初始化 结构体变量引用 结构体的有名定义:直白...

  • 【C语言笔记】<十九>结构体

    结构体的基本概念 结构体初始化 结构体的内存存储细节 结构体定义的方式 结构体类型的作用域 指向结构体的指针 结构...

  • 06-结构体和类

    结构体 结构体的初始化器 思考:下面代码能编译通过么? 自定义初始化器 窥探初始化器的本质 结构体内存结构 类 类...

  • 42_内存操作经典问题分析二

    1. 常见内存错误 (1) 结构体成员指针未初始化——野指针(2)结构体成员指针未分配足够的内存——越界(3)内存...

  • Android jni 结构体赋值失败,c结构体指针初始化

    c结构体如下: 在使用该结构体时,除了要注意对结构体的内存分配, 也不能忘了给结构体内的指针进行初始化并分配内存空...

  • 结构体

    结构体定义格式 定义结构体变量 结构体初始化 结构体内存分析 定义结构体类型并不会分配存储空间 只有定义结构体变量...

  • C结构体和链表

    一,结构体变量定义及初始化 二,无名结构体 备注:无名结构体很少使用 三,宏定义结构体 四,结构体嵌套 五,结构体...

网友评论

      本文标题:go结构体的初始化及内存布局

      本文链接:https://www.haomeiwen.com/subject/lsqpihtx.html