原文: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. 结构体比较

  1. 如果结构体的所有成员变量都可以比较,那么这个结构体是可以比较的。两个结构体的比较可以使用==或者!=。
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. 结构体嵌套和匿名成员

  1. 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
}
  1. 结构体字面量初始化没有快捷方式,必须遵循形状类型的定义。
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. 结构体方法

  1. 定义
    方法的声明和普通函数的声明类似,知识在函数名字前面多加了一个参数。这个参数把这个方法绑定到这个参数对应的类型上。
    附加的参数p成为方法的接收者, 它源于早先的面向对象语言,用来描述主调方法向对象发送消息。
type Point struct {
X int
Y int
}
func (p Point) print() {
fmt.Println(p.X, p.Y)
}
  1. 方法定义限制
    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()
}
  1. 指针接收者的方法
    由于主调函数会复制每一个实参变量,或者如果一个实参太大而我们希望避免复制整个实参,因此我们必须使用指针来传递变量的地址。这也同样适用于更新接收者我们将它绑定到指针类型。在调用方法的时候,编译器会对变量进行隐式转换。
    总结一下结构体方法可以成功调用的条件:
  • 实参接收者和形参接收者是同一类型,比如都是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 结构体和方法的更多相关文章

  1. 六、golang中的结构体和方法、接口

    结构体: 1.用来自定义复杂数据结构 2.struct里面可以包含多个字段(属性) 3.struct类型可以定义方法,注意和函数的区分 4.strucr类型是值类型 5.struct类型可以嵌套 6. ...

  2. GO开发[五]:golang结构体struct

    Go结构体struct Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性 ...

  3. golang结构体json格式化的时间格式

    golang结构体json格式化的时间格式 在我们开发中,经常会解析time.Time 往往前台传过来的时候,是个string 但是我们希望在结构体转成time.Time type Param str ...

  4. Golang结构体值的交换

    Golang结构体值的交换 一.添加结构体,多if暴力 最先遇到这个问题是在比编写PUT方法的接口时遇到. (我公司编写http put方法,是先解析json至StudentInput结构体中,通过i ...

  5. golang 结构体中的匿名接口

    golang 结构体中的匿名接口 代码示例 golang 中,可以给结构体增加匿名field,可参考 unknwon 大神的书. 匿名字段和内嵌结构体 但,golang同时也可以给结构体定义一个匿名i ...

  6. Go part 5 结构体,方法与接收器

    结构体 结构体定义 结构体的定义只是一种内存布局的描述(相当于是一个模板),只有当结构体实例化时,才会真正分配内存空间 结构体是一种复合的基本类型,通过关键字 type 定义为 自定义 类型后,使结构 ...

  7. go结构体的方法和普通函数

    package main import ( "fmt" "math" ) type vertex struct { X, Y float64 } //值接收者是 ...

  8. go 结构体与方法

    go 结构体与方法   go 结构体相当于 python 中类的概念,结构体用来定义复杂的数据结构,存储很多相同的字段属性 结构体的定义 1.结构体的定义以及简单实用 package main imp ...

  9. go结构体与方法

    go结构体相当于python中类的概念 结构体用来定义复杂的数据结构,存储很多相同的字段属性 1.结构体的定义以及简单实用 package main import ( "fmt" ...

随机推荐

  1. noi openjudge7627:鸡蛋的硬度

    http://noi.openjudge.cn/ch0206/7627/ 描述 最近XX公司举办了一个奇怪的比赛:鸡蛋硬度之王争霸赛.参赛者是来自世界各地的母鸡,比赛的内容是看谁下的蛋最硬,更奇怪的是 ...

  2. CentOS 7 利用qemu模拟ARM vexpress A9开发板

    听说qemu用于仿真arm很不错,今日就来试了一把.由于刚刚开始,了解的并不多.本文仅仅记录Qemu装载Linux kernel和busybox根文件系统的过程.后续将会深入了解仿真的其他内容. 先上 ...

  3. Linux中 cmake-3.x 编译安装以及man page添加

    首先回顾一下 cmake-2.x 的编译安装. ================ cmake-2.x编译安装说明 ================编译安装的命令: ./bootstrap --pref ...

  4. 常用的API

    API (application programming Interface)应用程序编程接口 java 是字典 Scanner类的功能可以实现从键盘输入到程序当中. 引用类型的一般使用步骤 ·1导包 ...

  5. 使用JQuery获取被选中的checkbox的value值

      上网查了一下,感觉一些人回答得真的是不知所云,要么代码不够简便.或者是有些想装逼成分等. 以下为使用JQuery获取input checkbox被选中的值代码: <html>    & ...

  6. fcntl和flock两个系统调用的区别

    总的来说,flock函数只能锁定整个文件,无法锁定文件的某一区域.而fcntl可以利用struct flock结构体,来实现文件里部分区域锁定的操作. 附:fcntl(文件描述词操作) 相关函数 op ...

  7. 关于quartz定期,起服务时不新增配置文件中的定期问题

    关于quartz定期,起服务时不新增配置文件中的定期问题 问题原因:生产环境中起服务,未加载配置文件信息,且quartz连接超时 查找原因发现 由于别人新建了一个定期文件 并将 quartz工厂类的i ...

  8. python入门pk小游戏

    import time import random flag = True while flag: player_win = 0 enemy_win = 0 for i in range(1, 4): ...

  9. MySql 8.0.11 客户端连接失败:2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: ....

    近期,换了新笔记本,重新安装了MySql数据库和客户端工具Navicat Premium 12.我是从官网上下载的MySql数据库,版本为8.0.11,链接:https://dev.mysql.com ...

  10. 【php设计模式】建造者模式

    <?php /** *建造者模式特点: * 1.客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象. * 2.每一个具体建造者都相对独立, ...