关于后端:整明白-Golang-struct-实例化和赋值

32次阅读

共计 4230 个字符,预计需要花费 11 分钟才能阅读完成。

Golang 中 struct 各种实例化和赋值形式,一会儿是值传递,一会儿又是指针,让人一头雾水,于是我决定梳理一下,整个明确。

先定义一个构造体,上面联合代码进行解说。

package main

import "fmt"

type Person struct {
    Name string
    Age int
    Descprtion string
}

实例一

p 以最惯例的形式实例化一个 struct,变量 p 失去一个 Person 构造体。

p := Person{}
p.Name = "小明"

fmt.Printf("p:%+v 变量地址:%p\n", p, &p)
fmt.Println("===========")

// result:
// p:{Name: 小明 Age:0 Descprtion:} 变量地址:0xc000078480
// ===========

实例二

变量 p1 由 p 赋值而来,因为 Golang 语言是 值传递,赋值后,对 p1 的批改并不会影响到 p;

从第一个输入也能够看得出,Golang 的赋值并不存在像 PHP 变量赋值时的 写时复制(copy on write)机制。

p1 := p
fmt.Printf("p1:%+v 变量地址:%p\n", p1, &p1) // 不存在写时复制
p1.Name = "小明 p1"
fmt.Printf("p:%+v 变量地址:%p\n", p, &p)
fmt.Printf("p1:%+v 变量地址:%p\n", p1, &p1)
fmt.Println("===========")

// result:
// p1:{Name: 小明 Age:0 Descprtion:} 变量地址:0xc0000784e0
// p:{Name: 小明 Age:0 Descprtion:} 变量地址:0xc000078480
// p1:{Name: 小明 p1 Age:0 Descprtion:} 变量地址:0xc0000784e0
// ===========

实例三

利用取地址符将 p 的地址赋值给 p2,变量 p2 是一个指针,寄存着指向 p 的地址。当 p2 批改了构造体中元素 Name 时,通过 p 拜访构造体对应的值也相应地产生了变动。

p2 := &p // 等同于 var p2 *Person = &p
fmt.Printf("p2:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p2, p2, &p2)
p2.Name = "小明 p2"
fmt.Printf("p1:%+v 变量地址:%p\n", p, &p)
fmt.Printf("p2:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p2, p2, &p2)
fmt.Println("===========")

// result:
// p2:&{Name: 小明 Age:0 Descprtion:} 指针变量指向地址(变量值):0xc000078480 变量地址:0xc000006030
// p1:{Name: 小明 p2 Age:0 Descprtion:} 变量地址:0xc000078480
// p2:&{Name: 小明 p2 Age:0 Descprtion:} 指针变量指向地址(变量值):0xc000078480 变量地址:0xc000006030
// ===========

实例四

变量 p3 由 new(Person) 得来。new 将开拓一块内存,返回内存地址给 p3,也即 p3 是一个指向这块内存的指针。

p3 是指向构造体的指针,它有两种形式能够操作构造体,p3.Age = 3*p3 = Person{Name: "小明 p3"}, 如果第二种形式后操作,将会笼罩第一种形式对构造体的批改。

因为 p3 是指针,当 p3 赋值给 p5 时,p5 也将指向这块内存地址。

p3 := new(Person)
fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
p3.Age = 3 // 等同于 (*p3).Age = 3
fmt.Println("================ 操作 Age ================")
fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
*p3 = Person{Name: "小明 p3",}
fmt.Println("================ 操作 Name ================")
fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
p5 := p3
fmt.Println("================ p5 := p3 ================")
fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
fmt.Printf("p5:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p5, p5, &p5)
p3.Name = "小明 p3 批改"
fmt.Println("================ p3 批改 ================")
fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
fmt.Printf("p5:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p5, p5, &p5)
fmt.Println("===========")

// result:
// p3:&{Name: Age:0 Descprtion:} 指针变量指向地址(变量值):0xc000078630 变量地址:0xc000006038
// ================ 操作 Age ================
// p3:&{Name: Age:3 Descprtion:} 指针变量指向地址(变量值):0xc000078630 变量地址:0xc000006038
// ================ 操作 Name ================
// p3:&{Name: 小明 p3 Age:0 Descprtion:} 指针变量指向地址(变量值):0xc000078630 变量地址:0xc000006038
// ================ p5 := p3 ================
// p5:&{Name: 小明 p3 Age:0 Descprtion:} 指针变量指向地址(变量值):0xc000078630 变量地址:0xc000006040
// ================ p3 批改 ================
// p3:&{Name: 小明 p3 批改 Age:0 Descprtion:} 指针变量指向地址(变量值):0xc000078630 变量地址:0xc000006038
// p5:&{Name: 小明 p3 批改 Age:0 Descprtion:} 指针变量指向地址(变量值):0xc000078630 变量地址:0xc000006040
// ===========

示例五

p4 的实例化形式也将失去一个指针,这种实例化形式与 p3 的实例化是雷同的,但 p4 的写法更常应用。

p4 := &Person{Name: "小明 p4",}
fmt.Printf("%+v %p\n", p4, &p4)

// result:
// &{Name: 小明 p4 Age:0 Descprtion:} 0xc000006048

附残缺代码:

package main

import "fmt"

type Person struct {
    Name string
    Age int
    Descprtion string
}

func main() {p := Person{}
    p.Name = "小明"

    fmt.Printf("p:%+v 变量地址:%p\n", p, &p)
    fmt.Println("===========")

    p1 := p
    fmt.Printf("p1:%+v 变量地址:%p\n", p1, &p1) // 不存在写时复制
    p1.Name = "小明 p1"
    fmt.Printf("p:%+v 变量地址:%p\n", p, &p)
    fmt.Printf("p1:%+v 变量地址:%p\n", p1, &p1)
    fmt.Println("===========")

    p2 := &p
    fmt.Printf("p2:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p2, p2, &p2)
    p2.Name = "小明 p2"
    fmt.Printf("p1:%+v 变量地址:%p\n", p, &p)
    fmt.Printf("p2:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p2, p2, &p2)
    fmt.Println("===========")

    p3 := new(Person)
    fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
    p3.Age = 3 // 等同于 (*p3).Age = 3
    fmt.Println("================ 操作 Age ================")
    fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
    *p3 = Person{Name: "小明 p3",}
    fmt.Println("================ 操作 Name ================")
    fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
    p5 := p3
    fmt.Println("================ p5 := p3 ================")
    fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
    fmt.Printf("p5:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p5, p5, &p5)
    p3.Name = "小明 p3 批改"
    fmt.Println("================ p3 批改 ================")
    fmt.Printf("p3:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p3, p3, &p3)
    fmt.Printf("p5:%+v 指针变量指向地址(变量值):%p 变量地址:%p\n", p5, p5, &p5)
    fmt.Println("===========")

    p4 := &Person{Name: "小明 p4",}
    fmt.Printf("%+v %p\n", p4, &p4)
}

End!

正文完
 0