内嵌结构体初始化零基础入门指南

简介: 内嵌结构体初始化零基础入门指南

/ Go 语言初始化内嵌结构体的技巧 /


 

一、概述

在 Go 语言中,经常会使用一个结构体内嵌另一个结构体,从而实现代码复用和扩展。但是初始化内嵌结构体也需要技巧,否则可能会引发一些问题。本文将详细探讨初始化内嵌结构体的各种方法。

主要内容包括:

  • 内嵌结构体语法回顾
  • 默认初始化行为
  • 指定初始化语法
  • 构造函数初始化
  • 初始化内嵌指针
  • 扩展阅读 - 内存布局
  • 初始化顺序及优化
  • 子结构重新分配
  • 匿名字段和初始化
  • 实际应用案例

通过学习这些知识,将能够高效并正确地初始化 Go 语言中的内嵌结构体,避免许多潜在问题。


 

二、内嵌结构体语法回顾

先简单回顾一下 Go 语言中内嵌结构体的语法:

type A struct {
  a int
}
type B struct {
  A // 内嵌结构体A
  b int
}

结构体 B 通过内嵌 A 后,就获得了 A 的字段和方法。这实现了类似继承的代码复用。


 

三、默认初始化行为

如果不特别指定,内嵌的结构体也会使用其类型的默认初始化:

type A struct {
  num int
  name string
}
type B struct {
  A
}
func main() {
  var b B
  // b.A是默认初始化的零值
}

这点需要注意,默认初始化可能不是期望的结果。


 

四、指定初始化语法

可以通过指定嵌套的成员名称来初始化:

type A struct {
  num int
}
type B struct {
  A
}
func main() {
  b := B{
    A: A{num: 1},
  }
  // b.A被显式初始化
}

或者对匿名内嵌字段直接初始化:

b := B{
  A{1},
}

这样就可以确保内嵌结构体初始化为所需值。


 

五、构造函数初始化

常会提供一个构造函数来初始化结构:

type A struct {
  num int
}
func NewA(n int) A {
  return A{num: n} 
}
type B struct {
  A
}
func main() {
  b := B{
    A: NewA(1),
  }
  //通过构造函数初始化
}

构造函数可以将初始化集中到一处,并提供必要的初始化逻辑。


 

六、初始化内嵌指针

如果内嵌的是一个指针:

type A struct {
  name string
}
type B struct {
  *A
}

那么就需要显示初始化内嵌指针:

b := B{
  A: &A{"John"},
}

不初始化就会造成空指针异常。


 

七、扩展阅读 - 内存布局

理解内嵌结构体的内存布局也有助于初始化:

type A struct {
  a int
  b int
}
type B struct {
  A
  c int
  d int 
}
// B内存布局
B {
  A.a 
  A.b
  c
  d
}

内嵌后的 A 对象依次放在 B 对象内存布局中。


 

八、初始化顺序及优化

正确的初始化顺序也很重要:

type A struct {
  name string
}
type B struct {
  A
  // 初始化A需要用到B的字段
  firstName string 
}
func NewB() B {
  return B {
    firstName: "John",
    A: A{name: "John"},
  }
}

构造函数可以控制初始化顺序,使之符合依赖关系。

如果可以,建议内嵌结构体放在字段列表开头,以优化内存布局。


 

九、子结构重新分配

有时候需要重新分配内嵌的子结构:

type A struct {
  name string
}
type B struct {
  A
}
func (b *B) Rename(newName string) {
  // 重新分配一个A对象
  b.A = A{name: newName} 
}

这在需要修改内嵌对象时很有用。


 

十、匿名字段和初始化

对于匿名内嵌字段,可以直接初始化:

type A struct {
  name string
}
type B struct {
  A // 内嵌匿名A
}
func main() {
  b := B{
    A: A{name: "Tom"},
  }
  // 等价简写
  b = B{
    A{"Tom"},
  }
}

匿名字段可以直接初始化,无需指定字段名。


 

十一、实际应用案例

来看一个实际的例子,一个用户结构体内嵌了地址结构体:

type Address struct {
  Province string
  City string
}
type User struct {
  Name string
  Age int
  Address 
}
func NewUser(name string, age int, addr Address) User {
  return User{
    Name: name,
    Age: age,
    Address: addr,
  }
}
func main() {
  addr := Address{
    Province: "BJ",
    City: "Beijing",
  }
  u := NewUser("Tom", 20, addr)
}

通过构造函数可以确保初始化顺序正确,不同的结构也可以通过内嵌组合在一起使用。


 

十二、总结

Go 语言中合理初始化内嵌结构体非常重要,需要注意初始化语法、顺序、依赖关系等问题。

通过构造函数、显示初始化、修改子结构等技巧可以正确高效地初始化内嵌的结构体。这是使用内嵌的基础,希望本文可以提供一些参考帮助。


目录
相关文章
|
3月前
|
C++
C++系列十四:结构体
C++系列十四:结构体
|
10月前
|
Go
Go语言初始化指南:结构体成员变量的正确方式
Go语言初始化指南:结构体成员变量的正确方式
162 0
|
28天前
|
Cloud Native
云原生部署问题之什么是结构体,并给出一个结构体的定义和初始化示例
云原生部署问题之什么是结构体,并给出一个结构体的定义和初始化示例
31 10
|
3月前
|
存储 C#
C#.Net筑基-类型系统②常见类型--结构体类型Struct
本文介绍了C#中的结构体(struct)是一种用户自定义的值类型,适用于定义简单数据结构。结构体可以有构造函数,能定义字段、属性和方法,但不能有终结器或继承其他类。它们在栈上分配,参数传递为值传递,但在类成员或包含引用类型字段时例外。文章还提到了`readonly struct`和`ref struct`,前者要求所有字段为只读,后者强制结构体存储在栈上,适用于高性能场景,如Span和ReadOnlySpan。
|
3月前
|
安全 编译器 C++
【C/C++ 基础知识 】 C++ 初始化大全:选择最适合您需求的方式
【C/C++ 基础知识 】 C++ 初始化大全:选择最适合您需求的方式
106 2
|
3月前
|
存储 编译器 Go
Go 语言数组基础教程 - 数组的声明、初始化和使用方法
数组用于在单个变量中存储相同类型的多个值,而不是为每个值声明单独的变量。 声明数组 在Go中,有两种声明数组的方式:
147 0
|
9月前
内存函数的简单使用和实现
内存函数的简单使用和实现
|
存储 前端开发 Java
二十三.SpringCloudConfig源码-初始化配置
今天这篇文章我们来分析一下Spring Cloud Config 配置中心的源码,这应该是Spring Cloud Netflix的源码分析的最后一篇。下一个系列我将会继续分析Spring Cloud Alibaba相关组件的源码。Spring Cloud Config 基础使用请移步 《[配置中心Spring Cloud Config](https://blog.csdn.net/u014494148/article/details/117253831)》
指针介绍及使用方法
指针介绍及使用方法
131 0
|
存储 安全 程序员
【C++】C++11简介 | 列表初始化 | 声明 | 范围for
【C++】C++11简介 | 列表初始化 | 声明 | 范围for
【C++】C++11简介 | 列表初始化 | 声明 | 范围for