GO结构体

1. 结构体

Go语言可以通过自定义的方式形成新的类型,结构体就是这些类型中的一种复合类型,结构体是由零个或多个任意类型的值聚合成的实体,每个值都可以称为结构体的成员。

结构体成员也可以称为“字段”,这些字段有以下特性:

  • 字段拥有自己的类型和值;
  • 字段名必须唯一;
  • 字段的类型也可以是结构体,甚至是字段所在结构体的类型。

使用关键字 type 可以将各种基本类型定义为自定义类型,基本类型包括整型、字符串、布尔等。结构体是一种复合的基本类型,通过 type 定义为自定义类型后,使结构体更便于使用。

结构体的定义格式如下:

type 类型名 struct {字段1 字段1类型字段2 字段2类型…
}

  • 类型名:标识自定义结构体的名称,在同一个包内不能重复。
  • struct{}:表示结构体类型,type 类型名 struct{}可以理解为将 struct{} 结构体定义为类型名的类型。
  • 字段1、字段2……:表示结构体字段名,结构体中的字段名必须唯一。
  • 字段1类型、字段2类型……:表示结构体各个字段的类型。

示例:

type Point struct {X intY int
}

颜色的红、绿、蓝 3 个分量可以使用 byte 类型:

type Color struct {R, G, B byte
}

结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存

1.1 实例化

实例化就是根据结构体定义的格式创建一份与格式一致的内存区域,结构体实例与实例间的内存是完全独立的。

基本的实例化形式:

结构体本身是一种类型,可以像整型、字符串等类型一样,以 var 的方式声明结构体即可完成实例化。

var ins T

1

T 为结构体类型,ins 为结构体的实例。

type Index struct {x inty int
}func main() {var myIndex Index//使用.来访问结构体的成员变量,结构体成员变量的赋值方法与普通变量一致。myIndex.y = 10myIndex.x = 20fmt.Println(myIndex) //{20 10}}
//如果不赋值 结构体中的变量会使用零值初始化
type Point struct {X intY int
}
func main() {//可以使用var p = Point{X: 1,Y: 2,}var p = Point{1,2,}fmt.Printf("%v,x=%d,y=%d",p,p.X,p.Y )
}

创建指针类型的结构体:

Go语言中,还可以使用 new 关键字对类型(包括结构体、整型、浮点数、字符串等)进行实例化,结构体在实例化后会形成指针类型的结构体。

ins := new(T)

1

  • T 为类型,可以是结构体、整型、字符串等。
  • ins:T 类型被实例化后保存到 ins 变量中,ins 的类型为 *T,属于指针。

下面的例子定义了一个玩家(Player)的结构,玩家拥有名字、生命值和魔法值:

	type Player struct {name  stringhp    intpower int}play := new(Player)play.power = 10play.name = "小米"play.hp = 150fmt.Println(*play)  //{小米 150 10}

取结构体的地址实例化:

在Go语言中,对结构体进行&取地址操作时,视为对该类型进行一次 new 的实例化操作,取地址格式如下:

ins := &T{}

其中:

  • T 表示结构体类型。
  • ins 为结构体的实例,类型为 *T,是指针类型。
type Commend struct {Name    stringVar     *intCommend string
}func newCommend(name string, Var *int, commend string) *Commend {return &Commend{name,Var,commend,}
}var version = 1func main() {m := newCommend("lct", &version, "test")fmt.Println(*m)  //{lct 0x5d4318 test}
}

1.2 匿名结构体

匿名结构体没有类型名称,无须通过 type 关键字定义就可以直接使用。

ins := struct {// 匿名结构体字段定义字段1 字段类型1字段2 字段类型2…
}{// 字段值初始化初始化字段1: 字段1的值,初始化字段2: 字段2的值,…
}

  • 字段1、字段2……:结构体定义的字段名。
  • 初始化字段1、初始化字段2……:结构体初始化时的字段名,可选择性地对字段初始化。
  • 字段类型1、字段类型2……:结构体定义字段的类型。
  • 字段1的值、字段2的值……:结构体初始化字段的初始值。

// 打印消息类型, 传入匿名结构体
func printMsg(msg *struct {id   intdata string
}) {fmt.Printf("type :%T,msg:%v", msg, msg)
}func main() {msg := &struct {id   intdata string}{21,"hello",}printMsg(msg) //type :*struct { id int; data string },msg:&{21 hello}
}

2. 方法

在Go语言中,结构体就像是类的一种简化形式,那么类的方法在哪里呢?

在Go语言中有一个概念,它和方法有着同样的名字,并且大体上意思相同,Go 方法是作用在接收器(receiver)上的一个函数,接收器是某种类型的变量,因此方法是一种特殊类型的函数。

接收器类型可以是(几乎)任何类型,不仅仅是结构体类型,任何类型都可以有方法,甚至可以是函数类型,可以是 int、bool、string 或数组的别名类型,但是接收器不能是一个接口类型,因为接口是一个抽象定义,而方法却是具体实现,如果这样做了就会引发一个编译错误invalid receiver type…

接收器也不能是一个指针类型,但是它可以是任何其他允许类型的指针。

一个类型加上它的方法等价于面向对象中的一个类

在Go语言中,类型的代码和绑定在它上面的方法的代码可以不放置在一起,它们可以存在不同的源文件中,唯一的要求是它们必须是同一个包的。

类型 T(或 T)上的所有方法的集合叫做类型 T(或 T)的方法集。

在面向对象的语言中,类拥有的方法一般被理解为类可以做的事情。在Go语言中“方法”的概念与其他语言一致,只是Go语言建立的“接收器”强调方法的作用对象是接收器,也就是类实例,而函数没有作用对象。

为结构体添加方法:

需求:将物品放入背包

面向对象的写法:

将背包做为一个对象,将物品放入背包的过程作为“方法”

type Bag struct {items []int
}func (b *Bag) Insert(item int) {b.items = append(b.items, item)
}func main() {var bag Bagbag.Insert(10)fmt.Println(bag.items) //[10]
}

(b*Bag) 表示接收器,即 Insert 作用的对象实例。每个方法只能有一个接收器

2.1 接收器

接收器的格式如下:

func (接收器变量 接收器类型) 方法名(参数列表) (返回参数) {函数体
}
  • 接收器变量:接收器中的参数变量名在命名时,官方建议使用接收器类型名的第一个小写字母,而不是 self、this 之类的命名。例如,Socket 类型的接收器变量应该命名为 s,Connector 类型的接收器变量应该命名为 c 等。
  • 接收器类型:接收器类型和参数类似,可以是指针类型和非指针类型。
  • 方法名、参数列表、返回参数:格式与函数定义一致。

接收器根据接收器的类型可以分为指针接收器、非指针接收器,两种接收器在使用时会产生不同的效果,根据效果的不同,两种接收器会被用于不同性能和功能要求的代码中。

指针类型的接收器:

指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的 this 或者 self。

由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的。

示例:

使用结构体定义一个属性(Property),为属性添加 SetValue() 方法以封装设置属性的过程,通过属性的 Value() 方法可以重新获得属性的数值,使用属性时,通过 SetValue() 方法的调用,可以达成修改属性值的效果:

type Property struct {val int
}// set val
func (p *Property) setVal(val int) {p.val = val
}//get valfunc (p *Property) getVal() int {return p.val
}func main() {p := new(Property)p.setVal(20)fmt.Println(p.getVal()) //20
}

非指针类型的接收器:

当方法作用于非指针接收器时,Go语言会在代码运行时将接收器的值复制一份,在非指针接收器的方法中可以获取接收器的成员值,但修改后无效。

点(Point)使用结构体描述时,为点添加 Add() 方法,这个方法不能修改 Point 的成员 X、Y 变量,而是在计算后返回新的 Point 对象,Point 属于小内存对象,在函数返回值的复制过程中可以极大地提高代码运行效率:

package main
import ("fmt"
)
// 定义点结构
type Point struct {X intY int
}
// 非指针接收器的加方法
func (p Point) Add(other Point) Point {// 成员值与参数相加后返回新的结构return Point{p.X + other.X, p.Y + other.Y}
}
func main() {// 初始化点p1 := Point{1, 1}p2 := Point{2, 2}// 与另外一个点相加result := p1.Add(p2)// 输出结果fmt.Println(result)
}

在计算机中,小对象由于值复制时的速度较快,所以适合使用非指针接收器,大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针

4. 给任意类型添加方法

Go语言可以对任何类型添加方法,给一种类型添加方法就像给结构体添加方法一样,因为结构体也是一种类型。

为基本类型添加方法:

在Go语言中,使用 type 关键字可以定义出新的自定义类型,之后就可以为自定义类型添加各种方法了。我们习惯于使用面向过程的方式判断一个值是否为 0,例如:

if  v == 0 {// v等于0
}

如果将 v 当做整型对象,那么判断 v 值就可以增加一个 IsZero() 方法,通过这个方法就可以判断 v 值是否为 0,例如:

if  v.IsZero() {// v等于0
}

为基本类型添加方法的详细实现流程如下:

package main
import ("fmt"
)
// 将int定义为MyInt类型
type MyInt int
// 为MyInt添加IsZero()方法
func (m MyInt) IsZero() bool {return m == 0
}
// 为MyInt添加Add()方法
func (m MyInt) Add(other int) int {return other + int(m)
}
func main() {var b MyIntfmt.Println(b.IsZero())b = 1fmt.Println(b.Add(2))
}

5. 匿名字段

结构体可以包含一个或多个匿名(或内嵌)字段,即这些字段没有显式的名字,只有字段的类型是必须的,此时类型也就是字段的名字。

匿名字段本身可以是一个结构体类型,即结构体可以包含内嵌结构体。

Go语言中的继承是通过内嵌或组合来实现的,所以可以说,在Go语言中,相比较于继承,组合更受青睐。


type User struct {id   intname string
}type Manager struct {User
}func (u *User) ToString() string {return fmt.Sprintf("User:%p,%+v", u, u)
}func main() {m := Manager{User{1, "lct"},}fmt.Printf("manger:%p\n", &m) //manger:0xc000094030fmt.Println(m.ToString())  //User:0xc000094030,&{id:1 name:lct}
}

有点类似于重写

type User struct {id   intname string
}type Manager struct {Usertitle string
}func (u *User) ToString() string {return fmt.Sprintf("User:%p,%+v", u, u)
}func (m *Manager) ToString() string {return fmt.Sprintf("Manger:%p,%+v", m, m)
}func main() {m := Manager{User{1,"lct",}, "hahah"}fmt.Println(m.ToString()) //Manger:0xc00001a0f0,&{User:{id:1 name:lct} title:hahah}fmt.Println(m.User.ToString())  //User:0xc00001a0f0,&{id:1 name:lct}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/714780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32 | 零基础 STM32 第一天

零基础 STM32 第一天 一、认知STM32 1、STM32概念 STM32:意法半导体基于ARM公司的Cortex-M内核开发的32位的高性能、低功耗单片机。 ST:意法半导体 M:基于ARM公司的Cortex-M内核的高性能、低功耗单片机 32:32位单片机 2、STM32开发的产品 STM32开发的产品&a…

【论文笔记】Improving Language Understanding by Generative Pre-Training

Improving Language Understanding by Generative Pre-Training 文章目录 Improving Language Understanding by Generative Pre-TrainingAbstract1 Introduction2 Related WorkSemi-supervised learning for NLPUnsupervised pre-trainingAuxiliary training objectives 3 Fra…

Java 网络面试题解析

1. Http 协议的状态码有哪些?含义是什么?【重点】 200:OK,客户端请求成功。 301:Moved Permanently(永久移除),请求的URL已移走。Response中应该包含一个Location URL,…

steam++加速问题:出现显示443端口被 vmware-hostd(9860)占用的错误。

目录 前言: 正文: 前言: 使用Steam对GitHub进行加速处理时,建议使用2.8.6版本。 下载地址如下:Release 2.8.6 BeyondDimension/SteamTools GitHub 下载时注意自己的系统位数 正文: 使用GitHub时会使…

NOC2023软件创意编程(学而思赛道)python初中组初赛真题

软件创意编程 一、参赛范围 1.参赛组别:小学低年级组(1-3 年级)、小学高年级组(4-6 年级)、初中组。 2.参赛人数:1 人。 3.指导教师:1 人(可空缺)。 4.每人限参加 1 个赛项。 组别确定:以地方教育行政主管部门(教委、教育厅、教育局) 认定的选手所属学段为准。 二、…

蓝桥杯Java B组历年真题(2013年-2021年)

一、2013年真题 1、世纪末的星期 使用日期类判断就行,这里使用LocalDate,也可以使用Calendar类 答案 2099 使用LocalDate import java.time.LocalDate; import java.time.format.DateTimeFormatter; // 1:无需package // 2: 类名必须Main, 不可修改p…

CentOS7 Hive2.3.8安装

CentOS7 Hive2.3.8 安装 建议从头用我的博客,如果用外教的文件到 一、9)步骤了,就用他的弄完,数据库不一样,在9步骤前还能继续看我的 一、 安装MySQL 0.0)查询mariadb,有就去0.1),没有就不管…

python3装饰器

装饰器 它允许你修改函数或类的行为,而不更改其源代码。实质上,装饰器是接受另一个函数作为参数并返回一个包装原始函数的新函数。这样,你可以在不修改原始函数的情况下,添加一些额外的功能或逻辑。 def time_cost(func):"…

美团分布式 ID 框架 Leaf 介绍和使用

一、Leaf 在当今日益数字化的世界里,软件系统的开发已经成为了几乎所有行业的核心。然而,随着应用程序的规模不断扩大,以及对性能和可扩展性的需求不断增加,传统的软件架构和设计模式也在不断地面临挑战。其中一个主要挑战就是如…

学生云服务器_学生云主机_学生云数据库_云+校园特惠套餐

2024年腾讯云学生服务器优惠活动「云校园」,学生服务器优惠价格:轻量应用服务器2核2G学生价30元3个月、58元6个月、112元一年,轻量应用服务器4核8G配置191.1元3个月、352.8元6个月、646.8元一年,CVM云服务器2核4G配置842.4元一年&…

自注意力机制(Self-Attention)

注意:本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站(【http://www.aideeplearning.cn】) Transformer模型中最关键部分就是自注意力(Self-Attention)机制,正如 Transformer 的论文的标题是“…

【Vue3】函数式编程(h 函数)

h 函数的原理就是 createVNode。可以使用 h 函数封装一些小组件。 <template><table border><tr><th>name</th><th>age</th><th>操作</th></tr><tr v-for"item in list" :key"item.age"&…

零拷贝技术深入分析

一、零拷贝 在前面的文章“深浅拷贝、COW及零拷贝”中对零拷贝进行过分析&#xff0c;但没有举例子&#xff0c;也没有深入进行展开分析。本文将结合实际的例程对零拷贝进行更深入的分析和说明。 在传统的IO操作中&#xff0c;以文件通过网络传输为例 &#xff0c;一般会经历以…

K8s控制器

控制器: Deployment: Deployment概述: replicaset:自动创建pod的控制器 Delpoyment控制器: pod的名字需要唯一,在这不写名字,利用标签进行创建 replicas:表示你想要克隆的数量,selector:通过标签.识别哪个pod是我创建出来的.这里的标签和后面元数据里的标签要一致. Cluster…

NCDA设计大赛获奖作品剖析:UI设计如何脱颖而出?

第十二届大赛简介 - 未来设计师全国高校数字艺术设计大赛&#xff08;NCDA&#xff09;开始啦&#xff01;视觉传达设计命题之一: ui 设计&#xff0c;你想知道的都在这里。为了让大家更好的参加这次比赛&#xff0c;本文特别为大家整理了以往NCDA大赛 UI 设计的优秀获奖作品&a…

2024年腾讯云优惠券_代金券_云服务器折扣券免费领取链接

腾讯云优惠代金券领取入口共三个渠道&#xff0c;腾讯云新用户和老用户均可领取8888元代金券&#xff0c;可用于云服务器等产品购买、续费和升级使用&#xff0c;阿腾云atengyun.com整理腾讯云优惠券&#xff08;代金券&#xff09;领取入口、代金券查询、优惠券兑换码使用方法…

【SpringBean】bean的作用域和bean的生命周期

目录 前言 一 bean的作用域 1. singleton——唯一 bean 实例 2. prototype——每次请求都会创建一个新的 bean 实例 3. request——每一次HTTP请求都会产生一个新的bean&#xff0c;该bean仅在当前HTTP request内有效 4. session——每一次HTTP请求都会产生一个新的 bean&…

程序员的金三银四求职宝典!

目录 ​编辑 程序员的金三银四求职宝典 一、为什么金三银四是程序员求职的黄金时期&#xff1f; 二、如何准备金三银四求职&#xff1f; 1. 完善简历 2. 增强技术能力 3. 提前考虑目标公司 4. 提前准备面试 三、程序员求职的常见面试题 1. 数据结构和算法 2. 数据库 …

一次电脑感染Synaptics Pointing Device Driver病毒的经历,分享下经验

没想到作为使用电脑多年的老司机也会电脑中病毒&#xff0c;周末玩电脑的时候突然电脑很卡&#xff0c;然后自动重启&#xff0c;奇怪&#xff0c;之前没出现这个情况。 重启后电脑开机等了几十秒&#xff0c;打开任务管理器查看开机进程&#xff0c;果然发现有个Synaptics Po…

LeetCode 刷题 [C++] 第121题.买卖股票的最佳时机

题目描述 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的…