Go语言中的自定义类型你了解吗
作者:金刀大菜牙 发布时间:2024-02-06 00:11:36
注:本篇文章主要介绍如何在 Go 语言中定义和使用自定义类型,涉及到一定的编程基础知识和语法。如有不熟悉的地方,建议先去学习相关的基础知识。可以阅读我的另一篇文章:解锁 Golang 数据类型:学会使用多种类型提高代码可读性和可维护性
1. 什么是自定义类型
在 Go 语言中,自定义类型指的是使用 type 关键字定义的新类型,它可以是基本类型的别名,也可以是结构体、函数等组合而成的新类型。自定义类型可以帮助我们更好地抽象和封装数据,让代码更加易读、易懂、易维护。
比如,我们可以定义一个自定义类型来表示某个领域中的概念,比如时间、日期、货币等。这些概念在不同的应用场景中有着不同的实现方式和表示方法,使用自定义类型可以使代码更具可读性,同时也便于进行后续的扩展和维护。
2. 如何定义自定义类型
在 Go 语言中,使用 type 关键字可以定义一个新的类型,语法如下:
type NewType OldType
其中,NewType 是新类型的名称,OldType 可以是任何基本类型或现有类型的别名,通过这种方式可以创建一个新类型,使得这个新类型具有与原有类型不同的特性。
比如,我们可以使用 type 关键字定义一个新类型来表示某个领域中的概念,比如日期:
type Date string
在这个例子中,我们使用 type 关键字定义了一个新类型 Date,它是 string 类型的别名。这个新类型可以用来表示日期,例如:
var today Date = "2023-04-29"
这里定义了一个变量 today,它的类型是 Date,也就是我们刚刚定义的日期类型。需要注意的是,虽然 Date 是 string 的别名,但是它与 string 类型是不同的类型,不能互相赋值或比较。
另外,我们也可以使用 type 关键字来定义一个结构体类型:
type Person struct {
Name string
Age int
}
在这个例子中,我们定义了一个 Person 结构体类型,它包含 Name 和 Age 两个字段。这个结构体类型可以用来表示一个人的基本信息。我们可以使用这个类型来创建一个 Person 变量:
var p Person
p.Name = "Tom"
p.Age = 18
需要注意的是,在 Go 语言中,自定义类型是强类型的,也就是说,不能随意将一个类型的值赋给另一个类型的变量,需要进行类型转换才能进行赋值。比如,我们不能将一个 int 类型的变量赋给一个 string 类型的变量,需要使用 strconv 包中的函数进行类型转换。
3. 自定义类型的方法
除了定义一个新类型外,我们还可以为自定义类型定义方法,方法是与类型相关联的函数,可以在该类型的实例上调用。方法使得类型具有更加丰富的行为,可以对该类型的数据进行操作、处理。
在 Go 语言中,使用 func 关键字定义方法,语法如下:
func (receiver Type) methodName(parameters) returnType {
// 方法体
}
其中,receiver 表示该方法的接收者,可以是该类型的值或指针,Type 表示该方法所属的类型,methodName 表示方法的名称,parameters 表示方法的参数,returnType 表示方法的返回值类型。
比如,我们可以为上面定义的 Person 结构体类型定义一个方法,来计算该人的年龄:
func (p Person) GetAge() int {
return p.Age
}
在这个例子中,我们定义了一个 GetAge 方法,它的接收者是一个 Person 类型的值,返回该人的年龄。我们可以通过以下方式来调用这个方法:
var p Person
p.Age = 18
age := p.GetAge()
这里首先创建了一个 Person 变量 p,并设置了其年龄为 18,然后调用了 p 的 GetAge 方法,返回其年龄,并赋值给 age 变量。
需要注意的是,Go 语言中的方法可以定义在任意类型上,而不仅仅是结构体类型,比如可以在 int 类型上定义方法,可以在自定义类型的别名上定义方法等等。
4. 自定义类型的嵌入和组合
自定义类型的嵌入和组合是 Go 语言中非常重要的概念,可以帮助我们更好地组织和重用代码。嵌入和组合本质上是一种代码复用的方式,可以将一个类型的特性复用到另一个类型中。
在 Go 语言中,使用结构体可以实现类型的嵌入和组合。嵌入表示将一个类型作为结构体的字段嵌入到另一个类型中,使得该类型可以使用被嵌入类型的特性。组合表示将多个类型组合在一起形成一个新类型,使得该类型可以同时具有多个类型的特性。
比如,我们可以定义一个新类型 Employee,它组合了 Person 和 Company 两个类型的特性:
type Person struct {
Name string
Age int
}
type Company struct {
Name string
Address string
}
type Employee struct {
Person
Company
Salary float64
}
在这个例子中,我们定义了 Person 和 Company 两个结构体类型,然后定义了一个新的 Employee 类型,它包含了 Person 和 Company 两个类型的特性,以及自己的薪水属性。通过这种方式,我们可以在 Employee 类型中复用 Person 和 Company 类型的特性,并在其基础上添加新的属性和方法。
在使用嵌入和组合时,我们可以通过结构体字面量来初始化一个结构体变量,比如:
var e Employee = Employee{
Person{Name: "Tom", Age: 30},
Company{Name: "Google", Address: "Mountain View"},
100000.0,
}
在这个例子中,我们使用了结构体字面量来初始化了一个 Employee 类型的变量 e,其中 Person 和 Company 字段都使用了字面量来初始化。
可以通过以下方式来访问 e 的属性和方法:
fmt.Println(e.Name) // 输出 "Tom"
fmt.Println(e.Age) // 输出 30
fmt.Println(e.Address) // 输出 "Mountain View"
fmt.Println(e.Salary) // 输出 100000.0
fmt.Println(e.GetAge()) // 输出 30
这里我们通过 e 来访问了它所嵌入的 Person 和 Company 类型的属性和方法,以及自己的薪水属性。需要注意的是,如果嵌入的类型中存在同名字段或方法,则可以通过类型名加字段名或方法名来访问指定类型的字段或方法。
5. 自定义类型的值接收者和指针接收者
在定义类型的方法时,可以使用值接收者或指针接收者,它们的区别在于方法接收者的类型是该类型的值还是指针。
值接收者表示方法的接收者是该类型的值,在方法中对该值进行修改不会影响到原始值。指针接收者表示方法的接收者是该类型的指针,在方法中对该指针指向的值进行修改会影响到原始值。
比如,我们可以为上面定义的 Person 类型定义一个修改年龄的方法:
func (p Person) SetAge(age int) {
p.Age = age
}
在这个例子中,我们定义了一个 SetAge 方法,它的接收者是一个 Person 类型的值,用于修改该人的年龄。但是,由于方法接收者是该类型的值,在方法中对其进行修改并不会影响到原始值,因此该方法并不能实现修改年龄的功能。
为了解决这个问题,我们可以使用指针接收者来定义该方法:
func (p *Person) SetAge(age int) {
p.Age = age
}
在这个例子中,我们使用了指针接收者来定义 SetAge 方法,它的接收者是一个 Person 类型的指针。通过使用指针接收者,我们可以在方法中修改该指针指向的值,从而实现修改年龄的功能。
需要注意的是,当类型的值较大时,使用指针接收者比值接收者更加高效,因为指针接收者传递的是指向该值的指针,而值接收者传递的是该值的副本,如果该值较大,则复制的开销会比较大。
6. 自定义类型的类型方法
除了定义实例方法,我们还可以定义类型方法。类型方法是属于类型的方法,而不是属于实例的方法。在类型方法中,可以使用类型名作为接收者,而不是实例的变量名。
比如,我们可以为 Person 类型定义一个类型方法,用于创建新的 Person 类型的变量:
func NewPerson(name string, age int) *Person {
return &Person{name, age}
}
在这个例子中,我们定义了一个 NewPerson 方法,它的接收者是 Person 类型的指针,用于创建一个新的 Person 类型的变量。在方法中,我们使用了类型名 Person 来创建了一个新的 Person 类型的变量,并返回该变量的指针。
可以通过以下方式来调用 NewPerson 方法:
p := NewPerson("Tom", 30)
fmt.Println(p) // 输出 "&{Tom 30}"
在这个例子中,我们调用了 NewPerson 方法,创建了一个新的 Person 类型的变量 p,并输出了该变量的指针。
需要注意的是,类型方法和实例方法之间的区别在于接收者的类型不同,类型方法的接收者是类型本身的指针,而实例方法的接收者是该类型的实例的指针或值。
7. 总结
在 Go 中,自定义类型是非常常见的操作,通过自定义类型,我们可以更好地组织和管理代码。在本文中,我们介绍了 Go 中自定义类型的基本概念和语法,包括类型别名、结构体、嵌入和组合、值接收者和指针接收者、类型方法等。
希望通过本文的介绍,能够帮助你更加深入地理解和掌握 Go 中自定义类型的相关知识,并能够在实际开发中灵活应用。
来源:https://juejin.cn/post/7227435228687335479
猜你喜欢
- 有一个查询如下: 代码如下:SELECT c.CustomerId, CompanyName FROM Customers c
- 1. position:static所有元素的默认定位都是:position:static,这意味着元素没有被定位,而且在文档中出现在它应该
- 我们在选择一件商品的时候,会先了解一些相关的商品信息,根据自己的需求和情况再进行选择。这种现象也同样适用于找工作,筛选一个岗位的重要环节,就
- 本文实例讲述了python实现根据图标提取分类应用程序,分享给大家供大家参考。具体方法如下:#!/usr/bin/python # -*-
- 一、准备工作:安装pywin32,后面开发需要pywin32的支持,否则无法完成与windows层面相关的操作。pywin32的具体安装及注
- 上面两个简单的Sql,我们从表面理解,查询的最终结果应该是一样的,但实际结果却和我们想象的不一样第一条sql查询的结果有一条数据第二条sql
- 每天工作忙,学会python自动收发邮件,代替你问候女友1、相关库介绍1)yagmailYet Another GMAIL/SMTP cli
- 概述:本控件使用 html+css+javascript模拟HTML内置的select元素,实现其部分方法与属性,也增加了一部分功能,并且从
- 1 概要deque 是一个双端队列, 如果要经常从两端append 的数据, 选择这个数据结构就比较好了, 如果要实现随机访问,不建议用这个
- 遇到的问题:在pytorch训练过程中突然out of memory。解决方法:1. 测试的时候爆显存有可能是忘记设置no_grad加入 w
- 游戏玩法根据神庙逃亡,实现一个人躲避僵尸的小游戏,主要的是精灵、精灵组之间相撞、相交的处理。游戏开始随机出现一定的僵尸,随机移动,玩家在一位
- 本文实例讲述了js控制div弹出层实现方法。分享给大家供大家参考。具体分析如下:这是个功能很好,且容易调用和控制的弹出层。感兴趣的朋友可以调
- 一、安装配置PHP1、下载Php的版本zip包之后,解压缩到指定目录。下载地址:http://www.php.net/downl
- 本文进通过实例,讲述通过 prototype 自定义方法的过程,旨在抛砖引玉,如果不对的地方,欢迎指正!prototype 是在 IE 4
- ⭐️网页解析利器parsel实战我们以实际的案例,来具体了解学习其功能。我们在这里重点讲解其两种方式。一个是XPATH,一个是CSS。我们以
- zabbix监控NginxA机器:zabbix服务端(192.168.234.128) B机器:zabbix客户端(192.168.234.
- 本文实例讲述了python中尾递归用法。分享给大家供大家参考。具体分析如下:如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递
- 今天星期天,因数据库太慢,最后决定将数据库进行重新整理. (假定数据库名称为:DB_ste) 1、根据现在的数据库的脚本创建一个脚本文件(F
- 默认情况下,PyCharm中如果有无法错误或者不符合PEP8规范代码下面会有波浪线,语法错误波浪线为红色(如下图的第10行),不符合PEP8
- 本文实例讲述了Python实现的查询mysql数据库并通过邮件发送信息功能。分享给大家供大家参考,具体如下:这里使用Python查询mysq