【转】golang 结构体和方法
原文:https://www.jianshu.com/p/b6ae3f85c683
---------------------------------------------------------------------------------------
1. 定义
结构体是将另个或者多个任意类型的命名变量组合在一起的聚合数据类型。
2. 成员变量
- 访问控制机制
如果一个结构体的成员变量名称是首字母大些的,那么这个变量是可导出的(即在其他包可以访问到)。
一个结构体可以同时包含可导出和不可导出的成员变量
type A struct {
Hour int //可导出
minute int //不可导出
}
- 限制
命名结构体类型s不可以定义一个拥有相同结构体类型s的成员变量,也就是一个聚合类型不可以包含它自己。但是s中可以定义一个s的指针类型,即*s。如下:
type B struct {
value int
//Next B //错误
Next *B //正确
}
3. 结构体比较
- 如果结构体的所有成员变量都可以比较,那么这个结构体是可以比较的。两个结构体的比较可以使用==或者!=。
type C struct {
A int
B string
}
c1 := C{A:1, B:"abc"}
c2 := C{A:1, B:"abc"}
c3 := C{A:2, B:"abc"}
fmt.Println(c1.A == c2.A && c1.B == c2.B) //true
fmt.Println(c1 == c2) //true 与上等价
fmt.Println(c1.A == c3.A && c1.B == c3.B) //false
fmt.Println(c1 == c3) //false 与上等价
2.和其他可比较的类型一样,可比较的结构体类型都可以作为map的键类型。
type C struct {
A int
B string
}
mp := make(map[C]int)
key := C{A:1, B:"abc"}
mp[key] = 9
fmt.Println(mp[C{A:1, B:"abc"}]) //9
4. 结构体嵌套和匿名成员
- go允许我们定义不带名称的结构体成员,只需要指定类型即可;这种结构体成员称作匿名成员。这个结构体成员的类型必须是一个命名类型或者指向命名类型的指针。正是因为有了这种结构体嵌套的功能,我们才能直接访问到我们需要的变量而不是指定一大串中间变量。
type Point struct {
X int
Y int
}
type Circle struct {
Point
}
var c Circle
c.X = 10 //等价于 c.Point.X = 10
c.Y = 10 //等价于 c.Point.Y = 10
type Wheel struct {
*Point
}
- 结构体字面量初始化没有快捷方式,必须遵循形状类型的定义。
type Point struct {
X int
Y int
}
type Circle struct {
Point
}
var c Circle
c = Circle{1,1} //错误
c = Circle{Point{1,1}} //正确
c = Circle{Point: Point{1,1}} //正确
3.因为“匿名成员”拥有隐式的名字,所以你不能在一个结构体里面定义两个相同类型的匿名成员,否则会引起冲突。由于匿名成员的名字是由它们的类型决定的,因此它们的可导出性也是由他们的的类型决定。在下面的例子中,point和circle这两个匿名成员是可导出的,即使这两个结构体是不可导出的(point和circle)。
type point struct {
X int
Y int
}
type circle struct {
point
}
type Wheel struct {
circle
}
var w Wheel
w.X = 8 // 等价于 w.circle.point.X = 8, w.X是可导出的,w.circle.point.X是不可导出的
5. 结构体方法
- 定义
方法的声明和普通函数的声明类似,知识在函数名字前面多加了一个参数。这个参数把这个方法绑定到这个参数对应的类型上。
附加的参数p成为方法的接收者, 它源于早先的面向对象语言,用来描述主调方法向对象发送消息。
type Point struct {
X int
Y int
}
func (p Point) print() {
fmt.Println(p.X, p.Y)
}
- 方法定义限制
go和许多其他面向对象的语言不同,它可以将方法绑定到除了指针类型和接口类型的任何类型上。可以很方便的为简单的类型(入整形、字符串、slice、map、甚至函数等)定义附加的行为。
//整形
type III int
func (i III) print() {
fmt.Println(i)
}
//函数
func Test() {
fmt.Println("test")
}
type FunT func()
func (f FunT) Print() {
fmt.Println(f)
}
func main() {
var f FunT
f = Test
f.Print()
}
- 指针接收者的方法
由于主调函数会复制每一个实参变量,或者如果一个实参太大而我们希望避免复制整个实参,因此我们必须使用指针来传递变量的地址。这也同样适用于更新接收者我们将它绑定到指针类型。在调用方法的时候,编译器会对变量进行隐式转换。
总结一下结构体方法可以成功调用的条件:
- 实参接收者和形参接收者是同一类型,比如都是T或者都是*T。(1,4,5,7)
- 实参接收者是T类型的变量而形参接收者是*T类型,编译器会隐式的获取变量的地址(3)。
- 实参接收者是T类型而形参接收者是T类型,编译器会隐式的获取实际的取值。(2,6)
其中8编译过程报错的原因是:编译器对T类型转化为T类型的隐式转化,只有实参接收者是变量才可以成功,因为无法获取临时变量的地址。
type Point struct {
X int
Y int
}
func (p Point) Print() {
fmt.Println(p.X, p.Y)
}
func (p *Point) ScaleBy(factor int) {
p.X *= factor
p.Y *= factor
}
func main() {
p := Point{1,1}
ptr := &p
p.Print() //1. 正确
ptr.Print() //2. 正确
p.ScaleBy(2) //3. 正确
ptr.ScaleBy(2) //4. 正确
Point{1,1}.Print() //5. 正确
(&Point{1,1}).Print() //6. 正确
(&Point{1,1}).ScaleBy( 2) //7. 正确
Point{1,1}.ScaleBy( 2) //8. 错误
}
- nil是一个合法的接收者:就像一些函数允许nil指针作为实参,方法的接收者允许是nil指针
type A struct {
Data int
}
func (a *A) FunPtrA() {
fmt.Println("FunPtrA")
}
func main() {
var ptrA *A
ptrA = nil
ptrA.FunPtrA() //FunPtrA
}
4. 通过结构体内嵌组成类型
这里主要讨论内嵌结构体和结构体指针后,对于源结构体定义函数的访问权限。
type A struct {
Data int
}
func (a A) FunA() {
fmt.Println(a.Data)
}
func (a *A) FunPtrA1() {
fmt.Println("FunPtrA1")
}
func (a *A) FunPtrA2() {
fmt.Println("FunPtrA2")
fmt.Println(a.Data)
}
type B struct {
A
}
type C struct {
*A
}
func main() {
var b B
b.FunA() //可以访问
b.FunPtrA1() //可以访问
b.FunPtrA2() //可以访问
var c C
//c.FunA() //不可访问
c.FunPtrA1() //可以访问
//c.FunPtrA2() //不可访问
c.A = &A{}
c.FunA() //可以访问
c.FunPtrA1() //可以访问
c.FunPtrA2() //可以访问
}
对于以上内容有疑问,欢迎留言讨论或者私信。转载请注明出处
作者:中电科苏云龙
链接:https://www.jianshu.com/p/b6ae3f85c683
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
【转】golang 结构体和方法的更多相关文章
- 六、golang中的结构体和方法、接口
结构体: 1.用来自定义复杂数据结构 2.struct里面可以包含多个字段(属性) 3.struct类型可以定义方法,注意和函数的区分 4.strucr类型是值类型 5.struct类型可以嵌套 6. ...
- GO开发[五]:golang结构体struct
Go结构体struct Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性 ...
- golang结构体json格式化的时间格式
golang结构体json格式化的时间格式 在我们开发中,经常会解析time.Time 往往前台传过来的时候,是个string 但是我们希望在结构体转成time.Time type Param str ...
- Golang结构体值的交换
Golang结构体值的交换 一.添加结构体,多if暴力 最先遇到这个问题是在比编写PUT方法的接口时遇到. (我公司编写http put方法,是先解析json至StudentInput结构体中,通过i ...
- golang 结构体中的匿名接口
golang 结构体中的匿名接口 代码示例 golang 中,可以给结构体增加匿名field,可参考 unknwon 大神的书. 匿名字段和内嵌结构体 但,golang同时也可以给结构体定义一个匿名i ...
- Go part 5 结构体,方法与接收器
结构体 结构体定义 结构体的定义只是一种内存布局的描述(相当于是一个模板),只有当结构体实例化时,才会真正分配内存空间 结构体是一种复合的基本类型,通过关键字 type 定义为 自定义 类型后,使结构 ...
- go结构体的方法和普通函数
package main import ( "fmt" "math" ) type vertex struct { X, Y float64 } //值接收者是 ...
- go 结构体与方法
go 结构体与方法 go 结构体相当于 python 中类的概念,结构体用来定义复杂的数据结构,存储很多相同的字段属性 结构体的定义 1.结构体的定义以及简单实用 package main imp ...
- go结构体与方法
go结构体相当于python中类的概念 结构体用来定义复杂的数据结构,存储很多相同的字段属性 1.结构体的定义以及简单实用 package main import ( "fmt" ...
随机推荐
- 【计算机视觉】关于OpenCV中GPU配置编译的相关事项
[计算机视觉]关于OpenCV中GPU配置编译的相关事项 标签(空格分隔): [计算机视觉] 前一段发现了OpenCV中关于GPU以及opencl的相关知识,打算升级一下对OpenCV的使用,但是发现 ...
- lnmp 命令 及其 TP5 部署遇到的一些问题
1.添加站点域名命令: lnmp vhost add; 2.重置mysql密码: 第一种方法:用军哥的一键修改LNMP环境下MYSQL数据库密码脚本 一键脚本肯定是非常方便.具体执行以下命令: wge ...
- 模型预测控制 MPC
使用MPC的原因:
- [LuoguP1074]靶形数独_搜索
靶形数独 题目链接:https://www.luogu.org/problem/P1074 数据范围:略. 题解: 传说中的大爆搜题啊. 我觉得这种题就是你能想到什么优化就直接上什么优化.... 这个 ...
- 【Python】【demo实验35】【基础实验】【排序】【选择法排序】
原题: 使用选择法对10个数字排序: 即取10个数中最小的放在第一个位置,再取剩下9个中最小的放在第二个位置... 我的源码: #!/usr/bin/python # encoding=utf-8 # ...
- MySQL中的InnoDB中产生的死锁深究
查考地址:https://blog.csdn.net/loophome/article/details/79867174 待研究中.....
- python3 虚拟环境的创建
创建虚拟环境的方法有很多种,我来分享一下我最常用的虚拟环境的创建方法和一些命令的使用, 什么是虚拟环境? 知道的可以略过,不知道的可以听我简单的说下.虚拟环境这四个字,一听你就明白什么意思了,首先理解 ...
- mysqlpump原理及实战
MySQL5.7之后多了一个备份工具:mysqlpump.它是mysqldump的一个衍生,mysqldump就不多说明了,现在看看mysqlpump到底有了哪些提升,可以查看官方文档,这里针对如何使 ...
- Kali Linux安装AWVS漏扫工具
Acunetix是全球排名前三的漏洞发现厂商,其全称(Acunetix Web Vulnerability Scanner)AWVS是业内领先的网络漏洞扫描器,其被广泛赞誉为包括最先进的SQL注入和X ...
- 我的第一个python web开发框架(2)——第一个Hello World
小白中午听完老菜讲的那些话后一直在思考,可想来想去还是一头雾水,晕晕呼呼的一知半解,到最后还是想不明白,心想:老大讲的太高深了,只能听懂一半半,看来只能先记下来,将明白的先做,不明白的等以后遇到再学. ...