Hi,你们好,我是明哥。git
在本身学习 Golang 的这段时间里,我写了详细的学习笔记放在个人我的微信公众号 《Go编程时光》,对于 Go 语言,我也算是个初学者,所以写的东西应该会比较适合刚接触的同窗,若是你也是刚学习 Go 语言,不防关注一下,一块儿学习,一块儿成长。github
个人在线博客:http://golang.iswbm.com
个人 Github:github.com/iswbm/GolangCodingTimegolang
在以前学过的数据类型中,数组与切片,只能存储同一类型的变量。若要存储多个类型的变量,就须要用到结构体,它是将多个容易类型的命令变量组合在一块儿的聚合数据类型。编程
每一个变量都成为该结构体的成员变量。数组
能够理解为 Go语言 的结构体struct和其余语言的class有相等的地位,可是Go语言放弃大量面向对象的特性,全部的Go语言类型除了指针类型外,均可以有本身的方法,提升了可扩展性。微信
在 Go 语言中没有没有 class 类的概念,只有 struct 结构体的概念,所以也没有继承,本篇文章,带你学习一下结构体相关的内容。函数
声明结构体性能
type 结构体名 struct { 属性名 属性类型 属性名 属性类型 ... }
好比我要定义一个能够存储我的资料名为 Profile 的结构体,能够这么写学习
type Profile struct { name string age int gender string mother *Profile // 指针 father *Profile // 指针 }
在 Go 语言中,咱们没法在结构体内定义方法,那如何给一个结构体定义方法呢,答案是可使用组合函数的方式来定义结构体方法。它和普通函数的定义方式有些不同,好比下面这个方法云计算
func (person Profile) FmtProfile() { fmt.Printf("名字:%s\n", person.name) fmt.Printf("年龄:%d\n", person.age) fmt.Printf("性别:%s\n", person.gender) }
其中fmt_profile
是方法名,而(person Profile)
:表示将 fmt_profile 方法与 Profile 的实例绑定。咱们把 Profile 称为方法的接收者,而 person 表示实例自己,它至关于 Python 中的 self,在方法内可使用 person.属性名
的方法来访问实例属性。
完整代码以下:
package main import "fmt" // 定义一个名为Profile 的结构体 type Profile struct { name string age int gender string mother *Profile // 指针 father *Profile // 指针 } // 定义一个与 Profile 的绑定的方法 func (person Profile) FmtProfile() { fmt.Printf("名字:%s\n", person.name) fmt.Printf("年龄:%d\n", person.age) fmt.Printf("性别:%s\n", person.gender) } func main() { // 实例化 myself := Profile{name: "小明", age: 24, gender: "male"} // 调用函数 myself.FmtProfile() }
输出以下
名字:小明 年龄:24 性别:male
上面定义方法的方式叫当你想要在方法内改变实例的属性的时候,必须使用指针作为方法的接收者。
package main import "fmt" // 声明一个 Profile 的结构体 type Profile struct { name string age int gender string mother *Profile // 指针 father *Profile // 指针 } // 重点在于这个星号: * func (person *Profile) increase_age() { person.age += 1 } func main() { myself := Profile{name: "小明", age: 24, gender: "male"} fmt.Printf("当前年龄:%d\n", myself.age) myself.increase_age() fmt.Printf("当前年龄:%d", myself.age) }
输出结果 以下,能够看到在方法内部对 age 的修改已经生效。你能够尝试去掉 *
,使用值作为方法接收者,看看age是否会发生改变。
当前年龄:24 当前年龄:25
至此,咱们知道了两种定义方法的方式:
那咱们如何进行选择呢?如下几种状况,应当直接使用指针作为方法的接收者。
有些状况下,以值或指针作为接收者均可以,可是考虑到代码一致性,建议都使用指针作为接收者。
无论你使用哪一种方法定义方法,指针实例对象、值实例对象均可以直接调用,而没有什么约束。这一点Go语言作得很是好。
为何标题的继承,加了双引号,由于Go 语言自己并不支持继承。
但咱们可使用组合的方法,实现相似继承的效果。
在生活中,组合的例子很是多,好比一台电脑,是由机身外壳,主板,CPU,内存等零部件组合在一块儿,最后才有了咱们用的电脑。
一样的,在 Go 语言中,把一个结构体嵌入到另外一个结构体的方法,称之为组合。
如今这里有一个表示公司(company)的结构体,还有一个表示公司职员(staff)的结构体。
type company struct { companyName string companyAddr string } type staff struct { name string age int gender string position string }
若要将公司信息与公司职员关联起来,通常都会想到将 company 结构体的内容照抄到 staff 里。
type staff struct { name string age int gender string companyName string companyAddr string position string }
虽然在实现上并无什么问题,但在你对同一公司的多个staff初始化的时候,都得重复初始化相同的公司信息,这作得并很差,借鉴继承的思想,咱们能够将公司的属性都“继承”过来。
可是在 Go 中没有类的概念,只有组合,你能够将 company 这个 结构体嵌入到 staff 中,作为 staff 的一个匿名字段,staff 就直接拥有了 company 的全部属性了。
type staff struct { name string age int gender string position string company // 匿名字段 }
来写个完整的程序验证一下。
package main import "fmt" type company struct { companyName string companyAddr string } type staff struct { name string age int gender string position string company } func main() { myCom := company{ companyName: "Tencent", companyAddr: "深圳市南山区", } staffInfo := staff{ name: "小明", age: 28, gender: "男", position: "云计算开发工程师", company: myCom, } fmt.Printf("%s 在 %s 工做\n", staffInfo.name, staffInfo.companyName) fmt.Printf("%s 在 %s 工做\n", staffInfo.name, staffInfo.company.companyName) }
输出结果以下,可见staffInfo.companyName
和 staffInfo.company.companyName
的效果是同样的。
小明 在 Tencent 工做 小明 在 Tencent 工做
在 Go 语言中,函数名的首字母大小写很是重要,它被来实现控制对方法的访问权限。
系列导读
24. 超详细解读 Go Modules 前世此生及入门使用