设为首页 收藏本站
查看: 1120|回复: 0

[经验分享] Golang面向对象编程

[复制链接]

尚未签到

发表于 2018-9-20 13:17:42 | 显示全部楼层 |阅读模式
  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)        // 未初始化;
  
     fmt.Println(DeputyCadres_2)
  
     fmt.Println(DeputyCadres_1 == nil)
  
     DeputyCadres_1 = new(Chairman)    //这种先声明再初始化的方式和直接初始化效果相同。
  
     fmt.Println(DeputyCadres_1)
  
     fmt.Println(DeputyCadres_1 == nil)
  
}
  

  

  

  
#以上代码执行结果如下:
  
{ 0}
  

  
&{ 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>
  
     Student // 这是我们自定义的结构体,我们可以在其前面加一个字段名称,如果不加的话就是匿名字段,那么默认>  
     area    int
  
     name string
  
}
  
func main() {

  
     yinzhengjie :=>  
         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>
  
     Student // 这是我们自定义的结构体,我们可以在其前面加一个字段名称,如果不加的话就是匿名字段,那么默认>  
     area    int
  
     name string
  
}
  


  
func MyEcho(p>  
     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 :=>  
         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>
  
     Student // 这是我们自定义的结构体,我们可以在其前面加一个字段名称,如果不加的话就是匿名字段,那么默认>  
     area    int
  
     name string
  
}
  


  
func MyEcho(p>  
     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 :=>  
         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

  
    >  
     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

  
    >  
     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}
  




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-598909-1-1.html 上篇帖子: 四、golang内置函数、递归、闭包、数组切片和map 下篇帖子: 微信消息加解密(GoLang)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表