原文: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. 在VMware上部署MOS(MirantisOpenStack-6.0)搭建全过程

    安装清单 MOS9.0系统镜像 1 MirantisOpenStack-6.0.iso ****首先创建3个仅主机模式网卡, 禁用DHCP,分别配置ip为 /10.20.0.0 /172.16.0.0 ...

  2. Odoo13 新变化:会计

    Odoo13将于2019年10月发布,本次发布也包含了大量的改进,例如,对会计的重构. 去掉了 account.invoice / account.invoice.line/ account.vouc ...

  3. Android netty客户端入门

    新建项目,加入netty库 implementation 'io.netty:netty-all:4.1.36.Final'

  4. Django边角料

    模型层表名自定义: class Record(models.Model): content=models.CharField(max_length=32,db_column='record_conte ...

  5. JavaSE基础(五)--Java运算符

    Java 运算符 计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量.我们可以把运算符分成以下几组: 算术运算符 关系运算符 位运算符 逻辑运算符 ...

  6. superslider样式

    .picScroll-left{ width: 1180px; position:relative; overflow: hidden; .bd{ ul{ li{ float: left; displ ...

  7. java中JDBC是什么?

    [学习笔记] JDBC是什么? JDBC即(java database connectivity数据连接).JDBC是Sun公司编的一堆类和方法,都封装在java.sql包中.你可以利用这堆类和方法来 ...

  8. java-filter and listener

    Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层. 使用 Serv ...

  9. Nodejs:单线程为什么能支持高并发?

      1.Nodejs是一个平台,构建在chrome的V8上(js语言解释器),采用事件驱动.非阻塞模型( c++库:libuv). 参考官方: Node.js is a platform built ...

  10. 6. Java基本数据类型

    Java 基本数据类型 变量就是申请内存来存储值.也就是说,当创建变量的时候,需要在内存中申请空间. 内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据. 因此,通过定义不 ...