当前位置: 首页 > news >正文

9.1go结构体

Go不是完全面向对象的,没有类的概念,所以结构体应该承担了更多的责任。

结构体定义

使用 type 和 struct 关键字定义:

type Person struct {

        Name string

        Age int

}

字段可以是任意类型,包括其他结构体或指针。

字段名以大写开头表示可导出(公开),小写表示私有(仅在包内可见)。

实例化

方式一:声明变量后赋值

        var p1 Person

        p1.Name = "Alice"

        p1.Age = 30

方式二:结构体字面量

        p2 := Person{Name: "Bob", Age: 25} // 指定字段名

        p3 := Person{"Charlie", 28} // 按字段顺序初始化(需注意顺序)

方式三:使用 new 函数(返回指针)

        p4 := new(Person)

        p4.Name = "Dave" // Go自动解引用,等价于 (*p4).Name

结构体的零值

当声明一个结构体变量而不初始化时,其字段会被赋予对应类型的零值。

var u Person
fmt.Println(u.Name) // 输出: ""
fmt.Println(u.Age)  // 输出: 0

结构体的构造函数

虽然 Go 不支持传统的构造函数,但可以通过定义函数来创建并初始化结构体实例,通常命名为 New【StructName】

func NewPerson(name string, age int) Person {return Person{Name: name,Age:  age,}
}p := NewPerson("Laura", 32)
fmt.Println(p.Name) 

嵌套与匿名字段

结构体可以嵌套其他结构体,实现组合(类似继承):

type Employee struct {

        Person // 匿名字段(嵌入Person结构体)

        Position string

}

这样的话,Employee就嵌套了Person,访问Employee的Name可以直接用e.Name,而不需要e.Person.Name,这就是结构体嵌套匿名字段的作用。

// 访问嵌套字段

e := Employee{Person{"Eve", 40}, "Engineer"}

fmt.Println(e.Name) // 直接访问Person的字段(字段提升)

结构体方法

结构体可以定义方法,接收者为值或指针:

Go中的方法是在函数前面加上一个接收者。比如,给Person结构体定义一个方法:

这里要注意,如果使用值接收者,修改不会影响原结构体,而指针接收者会改变原结构体的值。

// 值接收者(操作副本)

// 指针接收者(操作原对象)

func main() {p := Person{Age:  29,Name: "Diana",}p.Birthday()fmt.Println(p.Age) // 输出: 29 (未改变)p.BirthdayPointer()fmt.Println(p.Age) // 输出: 30 (已改变)}type Person struct {Name stringAge  int
}// 值接收者
func (p Person) Birthday() {p.Age += 1
}// 指针接收者
func (p *Person) BirthdayPointer() {p.Age += 1
}

继承

Employee 结构体嵌入了 Person结构体,因此 Employee 可以直接访问 Person的字段和方法

    e := Employee{Person{"Eve", 40}, "Engineer"}fmt.Println(e.Name, e.Age)e.Birthday()fmt.Println(e.Name, e.Age)e.BirthdayPointer()fmt.Println(e.Name, e.Age)

结构体作为参数

结构体作为参数传递给函数,如果是值传递,函数内部对结构体的修改不会影响原变量;如果是传递指针,则会修改原变量。

  • 值传递(拷贝副本)

直接将结构体作为值传递给函数,函数内部操作的是原结构体的副本,不会影响原对象。

示例:

package main

import "fmt"

type Point struct {

        X int

        Y int

}

// 值传递:修改副本,不影响原对象

func modifyValue(p Point) {

        p.X = 100

        fmt.Println("Inside modifyValue:", p) // 输出 {100 2}

}

func main() {

        p := Point{X: 1, Y: 2}

        modifyValue(p)

        fmt.Println("After modifyValue:", p) // 输出 {1 2}(原对象未改变)

}

适用场景:

结构体较小,拷贝成本低。

不需要修改原结构体的逻辑。

  • 指针传递(操作原对象)

传递结构体的指针(内存地址),函数内部操作的是原对象。

示例:

package main

import "fmt"

type Point struct {

        X int

        Y int

}

// 指针传递:修改原对象

func modifyPointer(p *Point) {

        p.X = 100

        fmt.Println("Inside modifyPointer:", *p) // 输出 {100 2}

}

func main() {

        p := &Point{X: 1, Y: 2}

        modifyPointer(p)

        fmt.Println("After modifyPointer:", p) // 输出 &{100 2}(原对象已改变)

}

适用场景:

结构体较大,避免拷贝开销。

需要修改原结构体的字段。

结构体字段覆盖

package mainimport "fmt"type Person struct {Name stringAge  int
}type Employee struct {Person // 嵌入Person结构体Name   string // 与Person中的Name字段同名Salary float64
}func main() {e := Employee{Person: Person{Name: "Alice", Age: 30},Name:   "Eve",Salary: 70000,}fmt.Println(e.Name)          // 输出: Eve (外层Employee的Name字段)fmt.Println(e.Person.Name)   // 输出: Alice (内层Person的Name字段)fmt.Println(e.Age)           // 输出: 30fmt.Println(e.Salary)        // 输出: 70000
}
  • Employee 结构体嵌入了 Person 结构体,并且两者都有一个名为 Name 的字段。
  • 当访问 e.Name 时,默认访问的是 Employee 结构体的 Name 字段("Eve"),这遮蔽了内层 Person 的 Name 字段。
  • 要访问内层 Person 的 Name 字段,需要使用 e.Person.Name

结构体方法覆盖

package mainimport "fmt"type Person struct {Name string
}func (p Person) Greet() {fmt.Printf("Hello, I'm %s from Person.
", p.Name)
}type Employee struct {PersonName string
}func (e Employee) Greet() {fmt.Printf("Hello, I'm %s from Employee.
", e.Name)
}func main() {p := Person{Name: "Alice"}e := Employee{Person: Person{Name: "Bob"},Name:   "Eve",}p.Greet() // 输出: Hello, I'm Alice from Person.e.Greet() // 输出: Hello, I'm Eve from Employee.// 调用嵌入结构体的方法e.Person.Greet() // 输出: Hello, I'm Bob from Person.
}
  • Employee 结构体定义了自己的 Greet 方法,覆盖了嵌入的 Person 的 Greet 方法。
  • 调用 e.Greet() 会执行 Employee 的 Greet 方法。
  • 如果需要调用被遮蔽的 Person 的 Greet 方法,可以通过 e.Person.Greet() 显式调用。

结构体可见性

如果结构体的名称或字段的名称以大写字母开头,那么其他包可以访问;否则,只能在当前包内访问。比如:

type person struct { // 小写,只能在包内使用

          name string

          age int

}

type Student struct { // 大写,公开,包外可见

        Name string

        Age int

}

结构体其他特性

比较

若所有字段可比较(非切片、map等),结构体可直接用 == 或 != 比较。

包含不可比较字段的结构体无法直接比较。

深浅拷贝

默认赋值是值拷贝(深拷贝)。

若字段含引用类型(如切片、指针),拷贝后共享底层数据。

作为Map的键需所有字段可比较:

type Point struct { X, Y int }

points := make(map[Point]string)

points[Point{1,2}] = "start"

匿名字段冲突

若多个匿名字段有同名字段,需显式指定:

type A struct { Name string }

type B struct { Name string }

type C struct { A; B }

c := C{}

c.A.Name = "Alice" // 必须明确指定

相关文章:

9.1go结构体

Go不是完全面向对象的,没有类的概念,所以结构体应该承担了更多的责任。 结构体定义 使用 type 和 struct 关键字定义: type Person struct { Name string Age int } 字段可以是任意类型,包括其他结构体或指针。 字段名以大写…...

Manus全球首个通用Agent,Manus AI:Agent应用的ChatGPT时刻

文章目录 前言Manus AI: 全球首个通用AgentManus AI: 技术架构与创始人经历AI Agent的实现框架与启示AI Agent的发展预测行业风险提示 前言 这是一篇关于Manus AI及其在通用人工智能领域的应用和前景的报告,主要介绍了Manus AI的产品定位、功能、技术架构、创始人经…...

【SAP-PP】生产版本维护

一、基本概念 生产版本:用于定义一种产品,不同的生产方式,包含物料清单(BOM)和工艺路线的信息,给生产带来更多的灵活性。在做产品需求计划时和产品生产时(创建生产订单、生产订单下达前和生产订…...

软考 中级软件设计师 考点笔记总结 day01

文章目录 软考1.0上午考点下午考点 软考1.11、数值及其转换2、计算机内数据表示2.1、定点数 - 浮点数2.2、奇偶校验 和 循环冗余校验 (了解)2.3、海明码 (掌握)2.4、机器数 软考1.0 上午考点 软件工程基础知识: 开发模型、设计原则、测试方…...

K8s控制器Deployment详解

回顾 ReplicaSet 控制器,该控制器是用来维护集群中运行的 Pod 数量的,但是往往在实际操作的时候,我们反而不会去直接使用 RS,而是会使用更上层的控制器,比如说 Deployment。 Deployment 一个非常重要的功能就是实现了 Pod 的滚动…...

【微知】Centos如何迁移到Anolis系统的失败记录?(yum -y install centos2anolis、centos2anolis.py)

背景 本文记录如何从centos 8迁移到anolis系统。 详细步骤 下载迁移repo wget https://mirrors.openanolis.cn/anolis/migration/anolis-migration.repo -O /etc/yum.repos.d/anolis-migration.repo下载centos2anolis工具包 yum -y install centos2anolis安装额外工具包 …...

在 macOS 上使用 CLion 进行 Google Test 单元测试

介绍 Google Test(GTest)是 Google 开源的 C 单元测试框架,它提供了简单易用的断言、测试夹具(Fixtures)和测试运行机制,使 C 开发者能够编写高效的单元测试。 本博客将介绍如何在 macOS 上使用 CLion 配…...

Python SQLite3 保姆级教程:从零开始学数据库操作

Python SQLite3 保姆级教程:从零开始学数据库操作 本文适合纯新手!无需任何数据库基础,跟着步骤操作即可掌握 SQLite3 的核心用法。 目标:让你像用记事本一样轻松操作数据库! 目录 什么是 SQLite3?环境准…...

深度解析:视频软编码与硬编码的优劣对比

视频编码 一、基本原理与核心技术 压缩原理 通过时空冗余消除实现数据压缩: 空间冗余:利用帧内预测(如DC/角度预测)消除单帧内相邻像素相似性。时间冗余:运动估计与补偿技术(ME/MC)减少连续帧间…...

Azure云生态系统详解:核心服务、混合架构与云原生概念

核心服务:深入掌握Azure SQL Database、Azure Database for PostgreSQL、Azure Database for MySQL的架构、备份恢复、高可用性配置(如Geo-Replication、自动故障转移组、异地冗余备份)。混合架构:熟悉Azure Arc(管理混…...

人工智能之数学基础:正交矩阵

本文重点 正交矩阵是线性代数中一个重要的特殊矩阵,它在许多领域都有广泛的应用。 什么是正交矩阵 如图所示,当矩阵A满足如上所示的条件的时候,此时我们就可以认为是正交矩阵,需要注意一点矩阵A必为方阵。 正交矩阵的充要条件 …...

分布式锁—7.Curator的分布式锁

大纲 1.Curator的可重入锁的源码 2.Curator的非可重入锁的源码 3.Curator的可重入读写锁的源码 4.Curator的MultiLock源码 5.Curator的Semaphore源码 1.Curator的可重入锁的源码 (1)InterProcessMutex获取分布式锁 (2)InterProcessMutex的初始化 (3)InterProcessMutex.…...

【笔记】STM32L4系列使用RT-Thread Studio电源管理组件(PM框架)实现低功耗

硬件平台:STM32L431RCT6 RT-Thread版本:4.1.0 目录 一.新建工程 二.配置工程 ​编辑 三.移植pm驱动 四.配置cubeMX 五.修改驱动文件,干掉报错 六.增加用户低功耗逻辑 1.设置唤醒方式 2.设置睡眠时以及唤醒后动作 ​编辑 3.增加测试命…...

C++什么是深复制和浅复制,构造函数和析构函数,哪一个可以写成虚函数,为什么?

在C之中深复制是指对于值类型复制它的值,对于指针类型不仅仅复制指针指向的值,还会重新分配一个内存空间用于放置复制的值(对动态分配的内存进行重新分配和内存复制),这种深复制不会出现悬空指针的问题,但是…...

从连接到交互:SDN 架构下 OpenFlow 协议的流程与报文剖析

在SDN架构中,交换机与控制器之间的通信基于 OpenFlow协议,其设计目的是实现控制平面与数据平面的解耦。以下是 交换机连接控制器 和 数据包进入交换机触发交互 的详细流程及协议报文分析: 一、交换机连接控制器的流程(初始化阶段&…...

第七课:Python反爬攻防战:Headers/IP代理与验证码

在爬虫开发过程中,反爬虫机制成为了我们必须面对的挑战。本文将深入探讨Python爬虫中常见的反爬机制,并详细解析如何通过随机User-Agent生成、代理IP池搭建以及验证码识别来应对这些反爬策略。文章将包含完整的示例代码,帮助读者更好地理解和…...

Golang学习笔记_47——访问者模式

Golang学习笔记_44——命令模式 Golang学习笔记_45——备忘录模式 Golang学习笔记_46——状态模式 文章目录 一、核心概念1. 定义2. 解决的问题3. 核心角色4. 类图 二、特点分析三、适用场景1. 编译器实现2. 财务系统3. UI组件系统 四、Go语言实现示例完整实现代码执行结果 五、…...

软件高级架构师 - 软件工程

补充中 测试 测试类型 静态测试 动态测试 测试阶段 单元测试中,包含性能测试,如下: 集成测试中,包含以下: 维护 遗留系统处置 高水平低价值:采取集成 对于这类系统,采取 集成 的方式&…...

IDEA 基础配置: maven配置 | 服务窗口配置

文章目录 IDEA版本与MAVEN版本对应关系maven配置镜像源插件idea打开服务工具窗口IDEA中的一些常见问题及其解决方案IDEA版本与MAVEN版本对应关系 查找发布时间在IDEA版本之前的dea2021可以使用maven3.8以及以前的版本 比如我是idea2021.2.2 ,需要将 maven 退到 apache-maven-3.…...

Qt之QGraphicsView图像操作

QGraphicsView图像操作:旋转、放大、缩小、移动、图层切换 1 摘要 GraphicsView框架结构主要包含三个主要的类QGraphicsScene(场景)、QGraphicsView(视图)、QGraphicsItem(图元)。QGraphicsScene本身不可见,是一个存储图元的容器,必须通过与之相连的QGraphicsView视图来显…...

NetCoreServer高级特性揭秘:自定义协议、会话管理和扩展机制

NetCoreServer高级特性揭秘:自定义协议、会话管理和扩展机制 【免费下载链接】NetCoreServer Ultra fast and low latency asynchronous socket server & client C# .NET Core library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K c…...

终极指南:如何使用RPGMakerDecrypter轻松解密游戏资源

终极指南:如何使用RPGMakerDecrypter轻松解密游戏资源 【免费下载链接】RPGMakerDecrypter Tool for extracting RPG Maker XP, VX and VX Ace encrypted archives. 项目地址: https://gitcode.com/gh_mirrors/rp/RPGMakerDecrypter RPGMakerDecrypter是一款…...

嵌入式开发代码版本比较工具与技巧

1. 嵌入式开发中的代码版本差异查看方法在嵌入式开发过程中,代码版本管理是每个工程师必须掌握的核心技能。随着项目迭代和功能更新,我们经常需要比较不同版本代码之间的差异,无论是为了代码审查、问题排查还是版本合并。作为一名嵌入式开发者…...

如何使用MQTTnet客户端工厂模式:对象创建与资源管理的终极指南

如何使用MQTTnet客户端工厂模式:对象创建与资源管理的终极指南 【免费下载链接】MQTTnet MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the …...

COMSOL 薄膜型声学超材料是利用薄膜结构单元在声波激励下的反共振特性,实现高于质量隔声定律...

COMSOL 薄膜型声学超材料是利用薄膜结构单元在声波激励下的反共振特性,实现高于质量隔声定律的隔声 STL隔声量 隔声系数 消声系数【1】薄膜材料本身需有较大弹性,且在低厚度情况下有良好的抗拉压性能,综合选取硅橡胶材料; 【2】附…...

别只改.prettierrc了!从Git配置到CI/CD,一劳永逸解决团队换行符冲突

从Git配置到CI/CD:彻底解决团队协作中的换行符冲突 跨平台协作开发时,换行符问题就像鞋里的一粒沙子——看似微不足道,却能让整个团队步履维艰。当Windows的CRLF遇上Unix的LF,不仅会导致Prettier报出恼人的Delete ␍错误&#xff…...

AI如何悄悄改变你的日常生活?5个你已离不开的AI应用场景

AI如何悄悄改变你的日常生活?5个你已离不开的AI应用场景 清晨被智能闹钟以最舒适的渐强音量唤醒,通勤路上听着音乐App精准推荐的歌单,晚上回家对着冰箱说出想吃的菜谱——这些场景中隐藏的AI技术,早已像水电一样成为生活基础设施。…...

Qwen3.5-35B-AWQ-4bit企业应用指南:教育题图解析、医疗影像初筛、办公文档理解

Qwen3.5-35B-AWQ-4bit企业应用指南:教育题图解析、医疗影像初筛、办公文档理解 1. 引言:当AI学会“看图说话”,企业效率能提升多少? 想象一下这样的场景:一位老师需要快速从几十张试卷中找出典型错题,一位…...

B+W 模块 BWU1664

BW (BihlWiedemann) BWU1664 是一款 ASi-3 专用模拟量输入模块,专为连接 Leuze ODSL 30 系列长距离激光测距传感器 设计,直接将测距数据接入 ASi 总线。一、核心定位系列:ASi-3 专用模拟量从站模块功能:2 路专用输入,直…...

蹲实验室折腾了两天FPGA终于把BISS-C协议编码器的坑填了。这次实现的Verilog方案有点意思,直接上硬货说说实现要点

雷尼绍BISS-C协议编码器verilog源码,支持18/26/32/36bit配置(也可以方便改成其他非标配置),支持最高10M时钟频率,由于是用FPGA纯verilog编写, 1)方便移植部署 2)可以支持多路编码器同时读取 3)成功在板卡跑…...