当前位置: 首页 > 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视图来显…...

人工智能之数学基础:对线性代数中逆矩阵的思考?

本文重点 逆矩阵是线性代数中的一个重要概念,它在线性方程组、矩阵方程、动态系统、密码学、经济学和金融学以及计算机图形学等领域都有广泛的应用。通过了解逆矩阵的定义、性质、计算方法和应用,我们可以更好地理解和应用线性代数知识,解决各种实际问题。 关于逆矩阵的思…...

嵌入式开发之串行数据处理

前题 前面几篇文章写了关于嵌入式软件开发时,关于串行数据处理的一些相关内容,有兴趣的可以看看《嵌入式开发:软件架构、驱动开发与串行数据处理》、《嵌入式软件开发之生产关系模型》和《嵌入式开发之Modbus-RTU协议解析》相关的内容。从业十…...

机器学习(六)

一,决策树: 简介: 决策树是一种通过构建类似树状的结构(颠倒的树),从根节点开始逐步对数据进行划分,最终在叶子节点做出预测结果的模型。 结构组成: 根节点:初始的数据集…...

结合unittest和pytest进行虚拟数据库测试

使用 pytest 和 MagicMock 模拟数据库操作,并测试假设的 create_user 函数,将用户添加到数据库中。 代码实现 from datetime import date from typing import List, Optional from unittest.mock import MagicMock from pydantic import BaseModel, Fi…...

Spring Boot 监听器(Listeners)详细教程

Spring Boot 监听器(Listeners)详细教程 目录 Spring Boot 监听器概述监听器核心概念最佳使用场景实现步骤高级配置详细使用场景总结 1. Spring Boot 监听器概述 Spring Boot 监听器(Listeners)基于 Spring Framework 的事件机制…...

工具介绍《githack》以及Git 命令行

一、Githack 工具介绍 Githack 是一个用于检测和利用网站 .git 目录泄露漏洞的安全工具。当网站错误配置导致 .git 目录可公开访问时,攻击者可通过该工具下载 .git 中的版本控制文件,并重建完整的项目源代码。 核心用途 检测 .git 目录泄露漏洞。从泄…...

【hello git】git rebase、git merge、git stash、git cherry-pick

目录 一、git merge:保留了原有分支的提交结构 二、git rebase:提交分支更加整洁 三、git stash 四、git cherry-pick 共同点:将 一个分支的提交 合并到 到另一个上分支上去 一、git merge:保留了原有分支的提交结构 现有一个模型…...

MR的环形缓冲区(底层)

MapReduce的大致流程: 1、HDFS读取数据; 2、按照规则进行分片,形成若干个spilt; 3、进行Map 4、打上分区标签(patition) 5、数据入环形缓冲区(KVbuffer) 6、原地排序&#xff…...

下载Hugging Face模型的几种方式

1.网页下载 直接访问Hugging Face模型页面,点击“File and versions”选项卡,选择所需的文件进行下载。 2.使用huggingface-cli 首先,安装huggingface_hub: pip install huggingface_hub 然后,使用以下命令下载模型&#xff1…...

Java 第十一章 GUI编程(2)

目录 GUI 事件处理 基本思路 添加事件监听器 对话框 实例 GUI 事件处理 对于采用了图形用户界面的程序来说,事件控制是非常重要的;到目前为止, 我们编写的图形用户界面程序都仅仅只是完成了界面,而没有任何实际的功能&…...