Golang中是否应该使用指针嵌入?

Golang中是否应该使用指针嵌入? 如下所示,Container 结构体有两个非指针嵌入字段:A[]B。它可能包含大量数据。

如果我修改代码,将 *Container 传递给 do() 函数,这将避免重新复制,因此应用程序应该更节省内存。然而,我想理解的是,我是否也应该将嵌入字段 A[]B 改为 *A[]*B 以避免复制?或者当传递 *Container 时,它们是否已经被复制了?

谢谢

package main

type Container struct {
	ID int
	// ... 更多字段
	A A // 还是 *A?
	B []B // 还是 []*B?
}

type A struct {
	ID int
	// ... 更多字段
}

type B struct {
	ID int
	// ... 更多字段
}

func main() {
	c := Container{
		ID: 1,
		A:  A{
			ID: 491,
		},
		B:  []B{
			{
				ID: 87,
			},
		},
	}
	
	do(c)
}

func do(c Container) {
	// 对 `c` 进行一些操作,但不需要修改。
}

更多关于Golang中是否应该使用指针嵌入?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

您无需将字段 A 和 []B 更改为指针类型来避免内存复制。当您将 *Container 传递给 do() 函数时,传递给函数的是 Container 对象的地址。

更多关于Golang中是否应该使用指针嵌入?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中,当传递*Container给函数时,只会复制指针本身(通常为8字节),而不是整个结构体。然而,结构体内部的嵌入字段是否会被复制取决于它们的类型。

对于你的代码示例:

package main

type Container struct {
    ID int
    A  A      // 值类型 - 会被完整复制
    B  []B    // slice - 复制slice头(指针+长度+容量)
}

type A struct {
    ID int
    // ... 更多字段
}

type B struct {
    ID int
    // ... 更多字段
}

func doByValue(c Container) {
    // c.A 被完整复制
    // c.B 复制了slice头,但底层数组共享
}

func doByPointer(c *Container) {
    // 只复制了指针(8字节)
    // 访问c.A和c.B时直接操作原结构体
}

func main() {
    c := Container{
        ID: 1,
        A: A{ID: 491},
        B: []B{{ID: 87}},
    }
    
    // 值传递 - 复制整个Container
    doByValue(c)
    
    // 指针传递 - 只复制指针
    doByPointer(&c)
}

关键点:

  1. 传递*Container:只复制指针,不会复制A字段或B slice的底层数据
  2. A字段(值类型):在Container内部,无论是否使用指针传递ContainerA都作为值存储
  3. B字段(slice):slice是引用类型,包含指向底层数组的指针

是否需要改为指针嵌入取决于:

// 如果A很大且频繁复制,使用指针
type Container struct {
    A *A
    B []*B  // 如果B元素很大且需要避免复制
}

// 示例:使用指针嵌入
func main() {
    c := &Container{
        ID: 1,
        A: &A{ID: 491},
        B: []*B{{ID: 87}},
    }
    
    do(c)
}

func do(c *Container) {
    // 直接操作原数据,无复制
    _ = c.A.ID
    _ = c.B[0].ID
}

性能考虑:

  • 小结构体(<指针大小):使用值类型
  • 大结构体或需要共享状态:使用指针
  • slice本身已包含指针,但元素如果是大结构体,考虑[]*B

内存布局示例:

// 值嵌入:A的数据直接存储在Container内存中
container := Container{A: A{data...}}

// 指针嵌入:Container存储指针,A的数据在堆上
container := Container{A: &A{data...}}

在只读场景且传递*Container的情况下,当前设计已避免大部分复制。是否需要进一步优化取决于AB的实际大小和使用模式。

回到顶部