西安网站设计建设公司,百度公司网站怎么做,湖北省京山县建设局网站,wordpress搜索被攻击本文详解了Go语言结构体的各个知识点#xff0c;最后介绍了空结构体的3种妙用。希望对你有帮助。 定义
结构体#xff0c;是一种自定义的数据类型#xff0c;由多个数据类型组合而成。用于描述一类事物相关属性。
定义方式#xff1a;
type 类型名 struct {字段名 字段类… 本文详解了Go语言结构体的各个知识点最后介绍了空结构体的3种妙用。希望对你有帮助。 定义
结构体是一种自定义的数据类型由多个数据类型组合而成。用于描述一类事物相关属性。
定义方式
type 类型名 struct {字段名 字段类型…
}//示例
type Animal struct {Name stringAge int
}实例化
结构体和结构体指针两者的实例化有所区别
提供多种写法灵活使用
//结构体实例化
//写法1
//var a Animal
//a.Name aaa
//a.Age 18
//写法2
a : Animal{ Name: dog,Age: 18,
}
fmt.Println(fmt.Sprintf(%T - %v, a, a)) //main.Animal - {dog 18}//结构体指针实例化
//写法1
var b *Animal
b new(Animal)
//写法2
//b : new(Animal)
//写法3
//b : Animal{}
b.Name cat //在底层是(*b).Name cat这是Go语言帮我们实现的语法糖
fmt.Println(fmt.Sprintf(%T - %v, b, b)) //*main.Animal - {cat 0}注意结构体指针必须手动初始化分配内存地址
匿名结构体
适用于临时数据存储的场景
var v struct {Name stringAge int
}
fmt.Println(v)空结构体
不占用内存空间
var v struct{}
fmt.Println(unsafe.Sizeof(v)) //0v1 : struct{}{}
fmt.Println(unsafe.Sizeof(v1)) //0构造函数
Go没有自带的构造函数采用自实现
方式1
结构体不复杂可以返回结构体类型值拷贝性能开销小
func NewPerson(name string, age int8) Person {return Person{name: name,age: age,}
}定义方式2
结构体复杂得返回结构体指针类型避免值拷贝产生的性能开销
func NewPerson(name string, age int8) *Person {return Person{name: name,age: age,sex: sex,country:country,province:province,city:city,town:town,address:address,}
}方法与接收者
方法Method是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者Receiver。接收者的概念就类似于PHP中的this或者 self。
方法与函数区别函数不属于任何类型方法属于特定类型。函数没有接收者方法有接收者。
标准格式
func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {函数体
}接收者类型两种
非指针类型发生值拷贝产生副本方法内修改字段只在方法内生效指针类型不产生副本方法内修改字段同步生效
func NewPerson(name string, age int8) *Person {return Person{name: name,age: age,}
}func (p *Person) Dream() {p.name aaafmt.Printf(%s的梦想是学好Go语言\n, p.name) //aaa的梦想是学好Go语言
}func main() {p1 : NewPerson(小王子, 25)p1.Dream()fmt.Println(p1) //{aaa 25}
}什么时候使用指针类型的接收者
需要修改接收者中的值接收者是拷贝代价比较大的大对象保证一致性在同一个文件中如果有某个方法使用了指针接收者那么其他的方法也建议使用指针接收者
注意点
1.接收者类型可以是任何类型不仅仅只针对结构体类型。但要注意下类型和方法定义需要在同一个包下面
type MyInt intfunc (i MyInt) SayInt() {fmt.Println(my type is MyInt)
}func main() {var i1 MyInti2 : MyInt(10)i1.SayInt()i2.SayInt()
}输出结果
my type is MyInt
my type is MyInt匿名字段
结构体允许其成员字段在声明时没有字段名而只有类型这种没有名字的字段就称为匿名字段
type User struct {Name stringGender stringAddress //匿名字段
}type Address struct {Province stringCity stringCreateTime string
}func main() {var u1 Useru1.Name 张三u1.Gender 男u1.Address.City 北京 //匿名字段默认使用类型名作为字段名u1.CreateTime 2019 //匿名字段可以省略但注意多个匿名字段下有相同字段名会编译失败所以建议不采用省略写法fmt.Println(u1)
}但需要注意字段名冲突问题所以不建议使用省略写法操作匿名字段
实现面向对象的“继承”特性
Go不是面向对象编程的语言但可以通过嵌套结构体的方式来实现面向对象的“继承”特性
type Animal struct {Name stringAge int
}func (a Animal) Say() {fmt.Println(fmt.Sprintf(1-my name is %s and age is %d, a.Name, a.Age))
}type Cat struct {Animal //嵌套结构体实现继承
}func main() {c1 : Cat{}c1.Name 加菲猫c1.Age 5c1.Say()//输出结果//1-my name is 加菲猫 and age is 5
}子类还可以重写父类的Say方法并且还能拥有自己的Run方法
func (c Cat) Say() {fmt.Println(fmt.Sprintf(2-my name is %s and age is %d, c.Name, c.Age))
}func (c Cat) Run() {fmt.Println(fmt.Sprintf(my name is %s还是跑步高手, c.Name))
}func main() {c1 : Cat{}c1.Name 加菲猫c1.Age 5c1.Say()c1.Run()//输出结果//2-my name is 加菲猫 and age is 5//my name is 加菲猫还是跑步高手
}标签tag
通过反射机制识别结构体的标签容错能力较差需要注意使用
标准格式
key1:value1 key2:value2使用注意事项
外层使用 反引号 包起来里边value需要使用 双引号 包起来KV之间使用冒号多个KV之间使用空格 注意冒号前后不要加其他符号
使用示例
goframe v2的标准路由注册就是使用标签tag的方式定义的大家感兴趣可以看下我们开源项目的代码
https://github.com/wangzhongyang007/goframe-shop-v2
结构体与JSON系列化
给结构体添加json标签然后做json序列化操作
首字母大写字段公开 会转换成json标签指定的字段名若未指定则使用自身字段名首字小写字段私有 不会输出因为这类字段仅在定义当前结构体的包中可访问
简单示例
type CardInfo struct {Title string json:titleDesc stringheight int json:height
}func main() {c1 : CardInfo{Title: 成长之星,Desc: balabala,height: 100,}data, _ : json.Marshal(c1)fmt.Println(string(data)) //{title:成长之星,Desc:balabala}str : {title:title111, desc:desc222, height:20}c2 : CardInfo{}_ json.Unmarshal([]byte(str), c2)fmt.Println(c2) //{title111 desc222 0}
}空结构体
上文为大家简单介绍了空结构体使用unsafe.SizeOf()方法明确知道了空结构体它不占用存储空间。
即“宽度”为0宽度描述了一个类型的实例所占用的存储空间的字节数
s : struct{}{}
fmt.Println(unsafe.Sizeof(s)) //0在项目代码中我们经常都会看到空结构体struct{}{}的使用它有什么作用适合什么场景使用呢
空结构体作用 请大家注意结构体包含一个指针和指针指向的数据下文所说的不占用内存其实指的是指针指向的数据为null但是空结构体最为一个变量它的指针肯定是占用内存空间的只是单用很小。 因为空结构体的值不占据内存空间的特性因此被广泛作为各种场景下的占位符使用。
一是节省资源二是空结构体本身就具备很强的语义即这里不需要任何值仅作为占位符。
空结构体使用场景
主要使用场景有3个
实现集合类型实现空通道实现方法接收者
下面逐个为大家详解
1.实现集合类型
Go语言本身是没有集合类型Set通常是使用map来替代。
但有个问题就是集合类型只需要用到key键不需要用到value值
如果value使用bool来表示实际会占用1个字节的空间为了节省空间这时空结构体就可以大显身手了
type Set map[int]struct{}func main() {s : make(Set)s.add(1)s.add(2)s.add(3)s.remove(2)fmt.Println(s.exist(1))fmt.Println(s)//输出//true//map[1:{} 3:{}]
}
func (s Set) add(num int) {s[num] struct{}{}
}
func (s Set) remove(num int) {delete(s, num)
}
func (s Set) exist(num int) bool {_, ok : s[num]return ok
}空结构体作为占位符不会额外增加不必要的内存开销很方便的就把问题给解决了
2.实现空通道
在Go语言 channel的使用场景中常常会遇到通知型 channel其不需要发送任何数据只是用于协调 Goroutine 的运行用于流转各类状态或是控制并发情况。
这类情况就特别适合使用空结构体只做个占位不浪费内存空间
func main() {ch : make(chan struct{})go worker(ch)// Send a message to a worker.ch - struct{}{}// Receive a message from the worker.-chprintln(AAA)//输出//BBB//AAA
}func worker(ch chan struct{}) {// Receive a message from the main program.-chprintln(BBB)// Send a message to the main program.close(ch)
}由于该 channel 使用的是空结构体因此也不会带来额外的内存开销
3.实现方法接收者
使用结构体类型的变量作为方法接收者有时结构体可以不包含任何字段属性。这种情况可以用int或者string来替代但它们都会占用内存空间所以使用空结构体是比较合适的。
并且也有利于未来针对该类型进行公共字段等的增加容易扩展和维护
type T struct{}func methodUse() {t : T{}t.Print()t.Print2()//输出//哈哈哈Print//哈哈哈Print2
}func (t T) Print() {fmt.Println(哈哈哈Print)
}
func (t T) Print2() {fmt.Println(哈哈哈Print2)
}总结
本文详解了Go语言结构体的各种知识点最后针对空结构体的作用和使用场景进行了详细的讲解。在之后的实际项目开发过程中只用占位不用实际含义那么我们就都可以使用空结构体可以极大的节省不必要的内存开销。
希望对大家有帮助兄弟们觉好留言哦。
坚持写作
这篇文章来自知识星球中劲仔的投稿欢迎加入我们坚持写作输出一起成长进步。