Golang面向对象编程-struct(结构体)

                                          作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.什么是面向对象编程

  面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP 达到了软件工程的三个主要目标:重用性、灵活性和扩展性。为了实现整体运算,每个对象都能够接收信息、处理数据和向其它对象发送信息。

二.面向对象编程常用名词介绍

  面向对象程序设计中的概念主要包括:对象、类、数据抽象、继承、动态绑定、数据封装、多态性、消息传递。通过这些概念面向对象的思想得到了具体的体现。

1>.对象(Object)

  可以对其做事情的一些东西。一个对象有状态、行为和标识三种属性。

2>.类(class)

  一个共享相同结构和行为的对象的集合。类(Class)定义了一件事物的抽象特点。通常来说,类定义了事物的属性和它可以做到的(它的行为)。举例来说,“狗”这个类会包含狗的一切基础特征,例如它的孕育、毛皮颜色和吠叫的能力。类可以为程序提供模版和结构。一个类的方法和属性被称为“成员”。

3>.封装(encapsulation):

  第一层意思:将数据和操作捆绑在一起,创造出一个新的类型的过程。第二层意思:将接口与实现分离的过程。

4>.继承

  类之间的关系,在这种关系中,一个类共享了一个或多个其他类定义的结构和行为。继承描述了类之间的“是一种”关系。子类可以对基类的行为进行扩展、覆盖、重定义。

5>.组合

  既是类之间的关系也是对象之间的关系。在这种关系中一个对象或者类包含了其他的对象和类。组合描述了“有”关系。

6>.多态

  类型理论中的一个概念,一个名称可以表示很多不同类的对象,这些类和一个共同超类有关。因此,这个名称表示的任何对象可以以不同的方式响应一些共同的操作集合。

7>.动态绑定

  也称动态类型,指的是一个对象或者表达式的类型直到运行时才确定。通常由编译器插入特殊代码来实现。与之对立的是静态类型。

8>.静态绑定

  也称静态类型,指的是一个对象或者表达式的类型在编译时确定。

9>.消息传递

  指的是一个对象调用了另一个对象的方法(或者称为成员函数)。

10>.方法

  也称为成员函数,是指对象上的操作,作为类声明的一部分来定义。方法定义了可以对一个对象执行那些操作。

三.Golang中的对象

  在Go语言中,也和 C 或者Python等其他语言一样,我们可以声明(自定义)新的类型,作为其它类型的属性或字段的容器。在Python或是C中,我们称这种数据类型为class类型,而在golang中它也有一个中文名字,叫做结构体。

1.定义一个新的类型

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main type Chairman struct { //其中“type...struct”表示定义数据类型的关键字,而Chairman则是我们定义类型的名字。
Name string //这里面的所有元素都是Chairman的属性,Name表示我们定义的名字的意思。
age int //这个顾名思义就知道是年龄喽,只不过我这里故意将首字母小写,但是你可别小瞧这个小写哟,以后我们在说它的功能。
}

2.声明以及定义的类型

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" type Chairman struct { //其中“type...struct”表示定义数据类型的关键字,而Chairman则是我们定义类型的名字。
Name string //这里面的所有元素都是Chairman的属性,Name表示我们定义的名字的意思。
age int //这个顾名思义就知道是年龄喽,只不过我这里故意将首字母小写,但是你可别小瞧这个小写哟,以后我们在说它的功能。
} func main() {
var Leader Chairman //声明结构体为自定义的Chairman;
var DeputyCadres_1 *Chairman //声明结构体为自定义的Chairman指针;
DeputyCadres_2 := new(Chairman) //用内置函数new进行了初始化&{ };
fmt.Println(Leader) //默认初始化为零值;
fmt.Println(DeputyCadres_1) //<nil> 未初始化;
fmt.Println(DeputyCadres_2)
fmt.Println(DeputyCadres_1 == nil)
DeputyCadres_1 = new(Chairman) //这种先声明再初始化的方式和直接初始化效果相同。
fmt.Println(DeputyCadres_1)
fmt.Println(DeputyCadres_1 == nil)
} #以上代码执行结果如下:
{ 0}
<nil>
&{ 0}
true
&{ 0}
false

3.初始化定义的类型

a>.先声明再赋值

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" type Chairman struct { //其中“type...struct”表示定义数据类型的关键字,而Chairman则是我们定义类型的名字。
Name string //这里面的所有元素都是Chairman的属性,Name表示我们定义的名字的意思。
age int //这个顾名思义就知道是年龄喽,只不过我这里故意将首字母小写,但是你可别小瞧这个小写哟,以后我们在说它的功能。
} func main() {
var p Chairman
p.Name = "习大大"
p.age = 64
fmt.Println(p)
} #以上代码执行结果如下:
{习大大 64}

b>.按照位置初始化

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" type Chairman struct { //其中“type...struct”表示定义数据类型的关键字,而Chairman则是我们定义类型的名字。
Name string //这里面的所有元素都是Chairman的属性,Name表示我们定义的名字的意思。
age int //这个顾名思义就知道是年龄喽,只不过我这里故意将首字母小写,但是你可别小瞧这个小写哟,以后我们在说它的功能。
} func main() {
var p Chairman
p = Chairman{
"习大大",
64,
}
fmt.Println(p)
} #以上代码执行结果如下:
{习大大 64}

c>.按照key和value的方式初始化

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" type Chairman struct { //其中“type...struct”表示定义数据类型的关键字,而Chairman则是我们定义类型的名字。
Name string //这里面的所有元素都是Chairman的属性,Name表示我们定义的名字的意思。
age int //这个顾名思义就知道是年龄喽,只不过我这里故意将首字母小写,但是你可别小瞧这个小写哟,以后我们在说它的功能。
} func main() {
var p Chairman
p = Chairman{
age:124,
Name:"毛爷爷",
}
fmt.Println(p)
} #以上代码执行结果如下:
{毛爷爷 124}

4.自定义struct案例及其用法案例展示

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main
import "fmt" type Student struct { // 声明一个新的类型叫Student
name string
age int
} func AgeConstrast(p1, p2 Student) (Student, int) { // 我们将定义的struct类型传递进来进行比较两个人的年龄,返回年龄大的那个人,并且返回年龄差
if p1.age>p2.age { // 比较 p1 和p2这两个人的年龄
return p1, p1.age-p2.age
}
return p2, p2.age-p1.age
}
func main() {
var yinzhengjie Student yinzhengjie.name, yinzhengjie.age = "尹正杰", 18 // 赋值初始化 bingan := Student{age:25, name:"饼干"} //按照key:value方式的初始化赋值 Leader:= Student{"习大大", 43} // 按照 struct定义顺序初始化值
yzj_bg, tb_diff := AgeConstrast(yinzhengjie, bingan) //将我们赋值好的数据传入我们定义的函数中,然后用两个参数接受返回值。
yzj_xdd, tp_diff := AgeConstrast(yinzhengjie, Leader)
bg_xdd, bp_diff := AgeConstrast(bingan, Leader)
fmt.Printf("当【·\033[31;1m%s\033[0m·】 和 【%s】 在一起时, 【%s】 比他大 【%d】 岁!\n",
yinzhengjie.name, bingan.name, yzj_bg.name, tb_diff)
fmt.Printf("当【·\033[31;1m%s\033[0m·】 和 【%s】 在一起时, 【%s】 比他大 【%d】 岁!\n",
yinzhengjie.name, Leader.name, yzj_xdd.name, tp_diff)
fmt.Printf("当【·\033[31;1m%s\033[0m·】 和 【%s】 在一起时, 【%s】 比他大 【%d】 岁!\n",
bingan.name, Leader.name, bg_xdd.name, bp_diff)
} #以上代码执行结果如下:
当【·尹正杰·】 和 【饼干】 在一起时, 【饼干】 比他大 【7】 岁!
当【·尹正杰·】 和 【习大大】 在一起时, 【习大大】 比他大 【25】 岁!
当【·饼干·】 和 【习大大】 在一起时, 【习大大】 比他大 【18】 岁!

5.自定义struct案例及其用法案例展示

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"math"
"fmt"
) type Point struct { //定义一个结构题体,你可以理解是是Python中的class
X,Y float64
} func (p Point)Distence(q Point) float64 { //给p对象定义一个Distence的方法,你可以理解绑定了一个Distence的方法。
return math.Hypot(q.X-p.X,q.Y-p.Y)
} func main() {
p := Point{1,2}
q := Point{4,6}
fmt.Println((p.Distence(q))) //类的调用方式,注意,如果定义就要如何调用!(这里是调用p的Distence方法。)
} #以上代码输出结果如下:
5

6.花式玩法struct案例展示(纯中文编程)

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" type 车的属性 struct {
名称 string
描述 string
是否需要备用 bool
} type 车的特性 []车的属性 //“车的特性”类型是包含结构体“车的属性”类型的数组切片,你可以理解是起了一个别名。 func (零件 车的特性) 备件方法()(车的信息 车的特性) { //给“车的特性”绑定一个叫“备件”的方法起名为“零件”。
for _,part := range 零件{
if part.是否需要备用 { //只将有备胎的车追加到“车的信息”这个空切片中。
车的信息 = append(车的信息,part)
}
}
return 车的信息
} type 汽车 struct { //“汽车”由“车身大小”组成
车身大小 string
车的特性 //没有给“车的特性”指定一个名称,我们是要保证实现“内嵌”。这样可以提供自动的委托,不需特殊的声明,
// 例如“汽车.备件方法()”和“汽车.车的特性.备件方法()”是等同的。
} var (
特斯拉 = 车的特性{
{"Tesla_90D(加速时间)", "100km/2.9s", true},
{"车身大小", "109.47万元", false},
{"颜色", "red", false},
} 宝马 = 车的特性{
{"BMW M4敞篷轿跑车(加速时间)", "100km/4.4s", true},
{"价格", "1,098,000美元", true},
{"倍耐力轮胎", "兰博基尼Huracan LP580-2前轮原配", true},
{"夏季冰丝汽车坐垫", "1088.00", true},
} 兰博基尼 = 车的特性{
{"Avetador(加速时间)", "100km/2.8s", true},
{"价格", "648.80-801.15万", true},
{"颜色", "黑色", false},
{"夏季冰丝汽车坐垫", "1088.00", true},
}
) func main() {
roadBike := 汽车{车身大小: "5037×2070×mm", 车的特性: 特斯拉}
mountainBike := 汽车{车身大小: "1678*1870*1398", 车的特性: 宝马}
recumbentBike := 汽车{车身大小: "4780*2030*1136", 车的特性: 兰博基尼}
fmt.Println(roadBike.备件方法())
fmt.Println(mountainBike.备件方法())
fmt.Println(recumbentBike.备件方法())
comboParts := 车的特性{}
comboParts = append(comboParts, mountainBike.车的特性...)
comboParts = append(comboParts, roadBike.车的特性...)
comboParts = append(comboParts, recumbentBike.车的特性...) fmt.Println(len(comboParts), comboParts[9:])
fmt.Println(comboParts.备件方法())
} #以上代码执行结果如下:
[{Tesla_90D(加速时间) 100km/2.9s true}]
[{BMW M4敞篷轿跑车(加速时间) 100km/4.4s true} {价格 1,098,000美元 true} {倍耐力轮胎 兰博基尼Huracan LP580-2前轮原配 true} {夏季冰丝汽车坐垫 1088.00 true}]
[{Avetador(加速时间) 100km/2.8s true} {价格 648.80-801.15万 true} {夏季冰丝汽车坐垫 1088.00 true}]
11 [{颜色 黑色 false} {夏季冰丝汽车坐垫 1088.00 true}]
[{BMW M4敞篷轿跑车(加速时间) 100km/4.4s true} {价格 1,098,000美元 true} {倍耐力轮胎 兰博基尼Huracan LP580-2前轮原配 true} {夏季冰丝汽车坐垫 1088.00 true} {Tesla_90D(加速时间) 100km/2.9s true} {Avetador(加速时间) 100km/2.8s true} {价格 648.80-801.15万 true} {夏季冰丝汽车坐垫 1088.00 true}]

四.Golang中的匿名字段

  结构体里的字段可以只有类型名,而没有字段名,这种字段称为匿名字段。匿名字段可以是一个结构体、切片等复合类型,也可以是 int 这样的简单类型。但建议不要把简单类型作为匿名字段。golang中每种类型只能有一个匿名域。可以用来实现oop中的继承。

1.匿名字段的初始化操作

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main
import "fmt"
type Student struct {
name string //第一个参数“name”叫做字段名称,第二个参数“string”叫做字段类型。
age int
speciality string
int //我们知道“int”是内置的数据类型,我们可以在前面加一个字段名称,如果不加就是用内置类型作为匿名字段。
}
type Classroom struct {
Student // 这是我们自定义的结构体,我们可以在其前面加一个字段名称,如果不加的话就是匿名字段,那么默认 Classroom就包含了Student 的所有字段。
area int
name string
}
func main() {
yinzhengjie := Classroom{ //我们给“Classroom”这个结构体定义了三个属性,一个是“Student”匿名字段,一个是“area”,还有一个是“name”。以下是赋值操作。
Student{
name:"尹正杰",
age:18,
speciality:"Basketball",
int:175,
},
100 ,
"Golang进阶之路",
}
fmt.Println(yinzhengjie)
} #以上代码执行结果如下:
{{尹正杰 18 Basketball 175} 100 Golang进阶之路}

2.匿名字段的查询操作

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main
import "fmt"
type Student struct {
Name string //第一个参数“name”叫做字段名称,第二个参数“string”叫做字段类型。
Age int
Speciality string
int //我们知道“int”是内置的数据类型,我们可以在前面加一个字段名称,如果不加就是用内置类型作为匿名字段。
}
type Classroom struct {
Student // 这是我们自定义的结构体,我们可以在其前面加一个字段名称,如果不加的话就是匿名字段,那么默认 Classroom就包含了Student 的所有字段。
area int
name string
} func MyEcho(p Classroom) { //该函数用来定义查看结构体信息的。
fmt.Printf("学生的姓名是:【%v】\n",p.Student.Name)
fmt.Printf("学生的身高是:【%d】\n",p.Student.int)
fmt.Printf("学生的爱好是:【%s】\n",p.Student.Speciality)
fmt.Printf("学生的身高是:【%d】\n",p.Student.int)
fmt.Printf("教室的面积是:【%v】\n",p.area)
fmt.Printf("教室的名称是:【%s】\n",p.name) }
func main() {
yinzhengjie := Classroom{ //我们给“Classroom”这个结构体定义了三个属性,一个是“Student”匿名字段,一个是“area”,还有一个是“name”。以下是赋值操作。
Student{
Name:"尹正杰",
Age:18,
Speciality:"Basketball",
int:175,
},
130 ,
"Golang进阶之路",
}
MyEcho(yinzhengjie)
} #以上代码执行结果如下:
学生的姓名是:【尹正杰】
学生的身高是:【175】
学生的爱好是:【Basketball】
学生的身高是:【175】
教室的面积是:【130】
教室的名称是:【Golang进阶之路】

3.匿名字段的修改

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main
import "fmt"
type Student struct {
Name string //第一个参数“name”叫做字段名称,第二个参数“string”叫做字段类型。
Age int
Speciality string
int //我们知道“int”是内置的数据类型,我们可以在前面加一个字段名称,如果不加就是用内置类型作为匿名字段。
}
type Classroom struct {
Student // 这是我们自定义的结构体,我们可以在其前面加一个字段名称,如果不加的话就是匿名字段,那么默认 Classroom就包含了Student 的所有字段。
area int
name string
} func MyEcho(p Classroom) { //该函数用来定义查看结构体信息的。
fmt.Printf("学生的姓名是:【%v】\n",p.Student.Name)
fmt.Printf("学生的身高是:【%d】\n",p.Student.int)
fmt.Printf("学生的爱好是:【%s】\n",p.Student.Speciality)
fmt.Printf("学生的身高是:【%d】\n",p.Student.int)
fmt.Printf("教室的面积是:【%v】\n",p.area)
fmt.Printf("教室的名称是:【%s】\n",p.name) }
func main() {
yinzhengjie := Classroom{ //我们给“Classroom”这个结构体定义了三个属性,一个是“Student”匿名字段,一个是“area”,还有一个是“name”。以下是赋值操作。
Student{
Name:"尹正杰",
Age:18,
Speciality:"Basketball",
int:175,
},
130 ,
"Golang进阶之路",
}
yinzhengjie.Student.Name = "yinzhengjie" //此处我们修改了“Classroom”的匿名字段“Student”的“Name”属性。
yinzhengjie.name = "Golang自动化运维工具" //这里我们修改了“Classroom”的“name”属性。
MyEcho(yinzhengjie)
} #以上代码执行结果如下:
学生的姓名是:【yinzhengjie】
学生的身高是:【175】
学生的爱好是:【Basketball】
学生的身高是:【175】
教室的面积是:【130】
教室的名称是:【Golang自动化运维工具】

五.面向对象之method(方法)

  好了,现在我们已经学会了struct的基本知识结合之前学习函数的知识。现在假设有这么一个场景,你定义了一个 struct 叫做长方形,你现在想要计算他的面积,那么按照我们以往的的思路应该会用下面的方式来实现:

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" const PI = 3.14 //定义pi的大小。 type Square struct { //定义一个长方形的类型
length,width float64
}
type Trapezoid struct { //定义一个梯形
UpperLength float64
BelowLength float64
Height float64
waist float64
}
type Circle struct {
radius float64
} func SquareArea(a Square) float64 {
return a.length * a.width
} func TrapezoidArea(a Trapezoid)float64 {
return (a.UpperLength + a.BelowLength)*a.Height/2
} func CircleArea(a Circle) float64 {
return PI*a.radius*a.radius
} func SquarePerimeter(a Square)float64 {
return (a.width + a.length)*2
} func TrapezoidPerimeter (a Trapezoid)float64 {
return a.UpperLength + a.BelowLength + a.waist*2
} func CirclePerimeter(a Circle) float64 {
return 2*PI*a.radius
} func main() {
a := Square{10,20}
fmt.Printf("正方形的面积是【%v】\n",SquareArea(a))
fmt.Printf("正方形的周长是【%v】\n",SquarePerimeter(a))
b := Trapezoid{10,20,5,15}
fmt.Printf("梯形的面积是【%v】\n",TrapezoidArea(b))
fmt.Printf("梯形的周长是【%v】\n",TrapezoidPerimeter(b))
c := Circle{5}
fmt.Printf("圆形的面积是【%v】\n",CircleArea(c))
fmt.Printf("圆形的周长是【%v】\n",CirclePerimeter(c))
}

1.初探method(方法)

  以上的方法的确可以实现我们想要的功能,但是每实现一个功能都得新写一个函数,需要重新给它起个名字。那如果让我们求五边形,六边形,多边形等等,就得写多个函数去实现。但是仔细看下以上的代码,其实就是实现了求面积和求周长的功能,如果我们可以将面积和周长分一个类,返回把正方形和梯形等求面积的都同意用一个Area方法去接受岂不更好,也不需要我们没次实现一个功能都得去写一个函数名。今天我们就讲解一下函数的另一种形态,带有接收者的函数,我们称为 method。因此,我们可以把上面的代码修改后一下

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import "fmt" const PI = 3.14 //定义pi的大小。 type Square struct { //定义一个长方形的类型
length,width float64
}
type Trapezoid struct { //定义一个梯形
UpperLength float64
BelowLength float64
Height float64
waist float64
}
type Circle struct {
radius float64
} func (a Square)Area()float64 { //我们可以给正方形设置求面积的(method)方法。
return a.width * a.length
}
func (a Trapezoid) Area() float64 { //我们可以给梯形设置求面积的方法。
return (a.UpperLength + a.BelowLength)*a.Height/2
} func (a Circle) Area() float64{ //我们圆形给正方形设置求面积的方法。
return PI*a.radius*a.radius
} func (a Square)Perimeter()float64 { //我们可以给正方形设置求周长的方法。
return (a.width + a.length)*2
} func (a Trapezoid)Perimeter()float64 {
return a.UpperLength + a.BelowLength + a.waist*2
} func (a Circle)Perimeter()float64 {
return 2*PI*a.radius
} func main() {
a := Square{10,20}
fmt.Printf("正方形的面积是【%v】\n",a.Area()) //注意其调用方式。
fmt.Printf("正方形的周长是【%v】\n",a.Perimeter())
b := Trapezoid{10,20,5,15}
fmt.Printf("梯形的面积是【%v】\n",b.Area())
fmt.Printf("梯形的周长是【%v】\n",b.Perimeter())
c := Circle{5}
fmt.Printf("圆形的面积是【%v】\n",c.Area())
fmt.Printf("圆形的周长是【%v】\n",c.Perimeter())
}

2.指针接受者

 /*
#!/usr/bin/env gorun
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/ package main import (
"fmt"
) type Point struct {
X,Y float64
} func (p *Point) ScaleBy(factor float64) { //想要修改p的值就得传指针类型"*Point",注意,如果这里传递不是指针的话讲无法对其属性进行更改!
p.X *= factor // 等价于:X = X * factor,对对象P进行操作,修改其私有属性。
p.Y *= factor
} func main() {
//两种调用方式:
p := Point{100,200}
p.ScaleBy(2) //姿势一:直接调用
fmt.Println(p) p1 := Point{100,200} //姿势二:声明结构体后再用指针指向
p2 :=&p1 //使用结构体调用,再取其内存地址
p2.ScaleBy(2)
fmt.Println(p2)
} #以上代码执行结果如下:
{200 400}
&{200 400}

Golang面向对象编程-struct(结构体)的更多相关文章

  1. Golang的面向对象编程【结构体、方法、继承、接口】

    Golang也支持面向对象编程.但与以前学过传统的面向对象编程语言有区别.1)Golang没有类class,Go语言的结构体struct和类class有相似的特性.2)Golang中不存在继承,方法重 ...

  2. golang 面向对象编程

    概述 Golang语言的面向对象与c++,py等语言有所不同,是由于Golang不支持继承:与上述支持聚合和继承的面向对象的语言不同,Golang只支持聚合(也叫做组合)和嵌入.聚合和嵌入的区别: t ...

  3. 3.11 Go Struct结构体

    3.11 Go Struct结构体 Golang支持OOP面向对象编程. Go的结构体struct如同python的class. Go基于struct实现OOP特性,只有组合composition这个 ...

  4. C# Struct结构体里数组长度的指定

    typedef struct Point{ unsigned short x; unsigned short y; }mPoint;//点坐标 typedef struct Line{ mPoint ...

  5. C语言 Struct 结构体在 Java 中的体现

    大一整个学期完成了 C 语言的学习,大二就进入了Java 的学习. 和C语言一样,我们都会尝试写一个小小的学生管理系统什么的,学习过 C 语言同学知道,在管理系统中 Struct 结构体是个很好用的东 ...

  6. go struct结构体

    struct结构体 用来自定义复杂数据结构 struct里面可以包含多个字段(属性),字段可以是任意类型 struct类型可以定义方法,注意和函数的区分 struct类型是值类型 struct类型可以 ...

  7. struct结构体在c和c++中的差别

    非常多次遇到这个struct的问题,今天在这里简单总结一下我的理解 一.struct在C 中的使用 1.单独使用struct定义结构体类型 struct Student { int id; int n ...

  8. Golang通过反射获取结构体的标签

    Golang通过反射获取结构体的标签 例子: package main import ( "fmt" "reflect" ) type resume struc ...

  9. C#基础--struct(结构体)

    结构体和类有点类似    我们定义一个类的时候    是class   类名   定义结构体的时候是 struct   结构体名 结构体的写法 struct Point { // public int ...

随机推荐

  1. HDOJ2099_整数的尾数

    一道我以为不会这么简单,然后暴力盲打竟然给过了的题. HDOJ2099_整数的尾数 #include<stdio.h> #include<stdlib.h> #include& ...

  2. python 中的三元表达式及lambda

    一.三元表达式 举一个简单的列子,很多地方都有这样的规定,比如用水或者用电,假设用水价格为3R/立方米,当你每个月用超过7立方米后,超出的水按照3.3R/立方米计价.然后写一个程序计算一个家庭每月的水 ...

  3. 初识nginx——内存池篇

    初识nginx——内存池篇 为了自身使用的方便,Nginx封装了很多有用的数据结构,比如ngx_str_t ,ngx_array_t, ngx_pool_t 等等,对于内存池,nginx设计的十分精炼 ...

  4. 使用kindeditor来替换ecshop的fckeditor编辑器,让ecshop可以批量上传图片

    老杨原创 kindeditor此编辑器可以让ecshop批量上传图片,可以插入代码,可以全屏编辑,可以插入地图.视频,进行更多word操作,设置字体. 步骤一:进入kindeditor的官网,http ...

  5. 关于Windows 2019 antimalware 进程占用CPU 过多的处理方法 关闭windows 病毒防护的方法

    0. 客户端打开报错 重启之后 响应速度很慢. 解决办法: 1. 打开组策略 gpedit.msc 2.  选择位置为 3. 查看 进程里面后台程序 antimalware 进程消失 即可

  6. msql 复杂练习

    https://blog.csdn.net/xiao__oaix/article/details/78122294 customer表branch 表account 表 depositor 表loan ...

  7. 设计模式之工厂模式(c++)

    问题描述 在面向对象系统设计中经常可以遇到以下的两类问题:1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口.这样我们可以通过声明 ...

  8. Test Scenarios for Filter Criteria

    1 User should be able to filter results using all parameters on the page2 refine search functionalit ...

  9. maven 引用另一个jar包 需要先打包在仓库里面 并在pom里面配置 才可以引用

    maven 引用另一个jar包 需要先打包在仓库里面 并在pom里面配置 才可以引用

  10. Centos7 Journald 指令

    Journald是为Linux服务器打造的新系统日志方式,它标志着文本日志文件的终结.现在日志信息写入到二进制文件,使用journalctl阅读,要获得这些信息,Linux管理员将需要一些实践. Re ...