ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## **章面向对象编程** 1) Golang 也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对 象语言。所以我们说 Golang 支持面向对象编程特性是比较准确的。 2) Golang 没有类(class),Go 语言的结构体(struct)和其它编程语言的类(class)有同等的地位,你可 以理解 Golang 是基于 struct 来实现 OOP 特性的。 3) Golang 面向对象编程非常简洁,去掉了传统 OOP 语言的继承、方法重载、构造函数和析构函 数、隐藏的 this 指针等等 4) Golang 仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其它 OOP 语言不 一样,比如继承 :Golang 没有 extends 关键字,继承是通过匿名字段来实现。 5) Golang 面向对象(OOP)很优雅,OOP 本身就是语言类型系统(type system)的一部分,通过接口 (interface)关联,耦合性低,也非常灵活。后面同学们会充分体会到这个特点。也就是说在 Golang 中面 向接口编程是非常重要的特性。 **结构体与结构体变量(实例/对象)的关系示意图** ![](https://img.kancloud.cn/b8/69/b869b84eef1c7c3bb1c7b793b2eb6d8b_745x294.png) 对上图的说明 1) 将一类事物的特性提取出来(比如猫类), 形成一个新的数据类型, 就是一个结构体。 2) 通过这个结构体,我们可以创建多个变量(实例/对象) 3) 事物可以猫类,也可以是 Person , Fish 或是某个工具类。 ![](https://img.kancloud.cn/ca/ad/caadfe30bfc19c70618ac813a709bd77_876x92.png) **快速入门\-面向对象的方式(struct)解决养猫问题** ![](https://img.kancloud.cn/72/05/720504cafd537b207b38364b788adfc0_641x455.png) 1) 结构体是自定义的数据类型,代表一类事物. 2) 结构体变量(实例)是具体的,实际的,代表一个具体变量 **结构体变量(实例)在内存的布局(重要!)** ![](https://img.kancloud.cn/36/44/364468b79efb629f15ef8d59ca7e7497_805x246.png) **如何声明结构体** ``` type 结构体名称 struct { field1 type field2 type } ``` **字段/属性** 1) 从概念或叫法上看: 结构体字段 \= 属性 \= field (即授课中,统一叫字段) 2) 字段是结构体的一个组成部分,一般是基本数据类型、数组,也可是引用类型。比如我们前面定 义猫结构体 的 Name string 就是属性 **注意事项和细节说明** 1) 字段声明语法同变量,示例:字段名 字段类型 2) 字段的类型可以为:基本类型、数组或引用类型 3) 在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值(默认值),规则同前面讲的 一样: 布尔类型是 false ,数值是 0 ,字符串是 ""。 数组类型的默认值和它的元素类型相关,比如 score \[3\]int 则为\[0, 0, 0\] 指针,slice,和 map 的零值都是 nil ,即还没有分配空间。 ![](https://img.kancloud.cn/d9/63/d96391079126f4d61170b00339c5d066_577x409.png) ![](https://img.kancloud.cn/49/14/49147b055554d23d2eaf6d6ec4656f5f_518x361.png) 4) 不同结构体变量的字段是独立,互不影响,一个结构体变量字段的更改,不影响另外一个, 结构体 是值类型。 ![](https://img.kancloud.cn/a3/43/a343e339da0944cda602c8a0aa94316f_373x91.png) ![](https://img.kancloud.cn/5d/f1/5df11509f66ab2f1d4c6e82501e95464_542x221.png) ![](https://img.kancloud.cn/3e/ec/3eec7b2c7320695cf78758c9aa6c0591_419x246.png) #### **创建结构体变量和访问结构体字段** 方式1-直接声明 var 结构体名 结构体 方式2-{} var personPerson=Person{} ![](https://img.kancloud.cn/46/e3/46e364f54038d4b9f5181c7058392964_665x227.png) 方式3-& 案例:varperson\*Person=new(Person) ![](https://img.kancloud.cn/06/ee/06eec1f94d980bdb672fc06eacfac664_1046x453.png) 方式4-{} 案例:varperson\*Person=&Person{} ![](https://img.kancloud.cn/3a/43/3a43ab6a96b469e129b8ffa26238a658_816x434.png) **说明:** 1)第3种和第4种方式返回的是结构体指针。 2)结构体指针访问字段的标准方式应该是:(\*结构体指针).字段名,比如(\*person).Name="tom" 3)但go做了一个简化,也支持结构体指针.字段名,比如person.Name="tom"。更加符合程序员 使用的习惯,go编译器底层对person.Name做了转化(\*person).Name。 **struct类型的内存分配机制** ![](https://img.kancloud.cn/81/bd/81bdc1f2ff109315a8c9f05e7ceb9903_1037x594.png) ![](https://img.kancloud.cn/a9/ce/a9ce4fec0f4ac2157b2c16d541471cce_831x475.png) ![](https://img.kancloud.cn/62/aa/62aa6975f1cfce0877a1e431a1a93ad7_1094x761.png) ![](https://img.kancloud.cn/99/5e/995e6c42913cfa51c6a279c7d0115e5d_956x217.png) ![](https://img.kancloud.cn/d2/3e/d23e0976a48d5c49ab51c7cc3bc5dfed_1009x514.png) ![](https://img.kancloud.cn/91/d2/91d273283a0c03fd19d3554f75420f4d_872x263.png) **1)结构体的所有字段在内存中是连续的** **在下面的代码中r1中有四个int 在内存中是连续的地址为16进制数那么相差8个数那么就相差8个字节逢8进一 好处是根据地址加减寻找非常快** ![](https://img.kancloud.cn/1b/67/1b679922cbd479eb2b46504b9d2c9c1a_708x18.png) ![](https://img.kancloud.cn/ce/f9/cef9232ac6548964e185eef85b434f39_617x700.png) ![](https://img.kancloud.cn/a1/dc/a1dc4b63d04d90eab0b83654c903eb3d_871x241.png) 2)结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类型) ![](https://img.kancloud.cn/5a/66/5a6649e51c50aa3ebb30231836163ec6_976x411.png) 3)结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转 ![](https://img.kancloud.cn/fe/60/fe60fccb36d6e8e544ff09e52ceb09a3_944x382.png) 4)struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化。 ![](https://img.kancloud.cn/c7/41/c741ee0041a0dbc673d1049acbae0369_918x215.png) ![](https://img.kancloud.cn/10/31/10312b5f42377af83fbb538e8860341c_746x466.png) ## **二:方法** Golang中的方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct。 **方法的声明和调用** ``` typeAstruct{ Numint } func(aA)test(){ fmt.Println(a.Num) } 对上面的语法的说明 1)func(aA)test(){}表示A结构体有一方法,方法名为test 2)(aA)体现test方法是和A类型绑定的 ``` ![](https://img.kancloud.cn/46/42/4642b758ab1ccce910a42a7c53bf7737_817x571.png) 对上面的总结 1)test方法和Person类型绑定 2)test方法只能通过Person类型的变量来调用,而不能直接调用,也不能使用其它类型变量来调用 ![](https://img.kancloud.cn/14/a0/14a0fb51c63955c7ba7e6bf1b5710f2e_589x116.png) 3)func(pPerson)test(){}...p表示哪个Person变量调用,这个p就是它的副本,这点和函数传参非常相似 4)p这个名字,有程序员指定,不是固定,比如修改成person也是可以 方法的调用和传参机制原理:(重要!) 方法的调用和传参机制和函数基本一样,不一样的地方是方法调用时,会将调用方法的变量,当做实参也传递给方法。下面我们举例说明。 ![](https://img.kancloud.cn/07/f1/07f1695850ccdf1143bc776b98ada002_821x425.png) 说明: 1)在通过一个变量去调用方法时,其调用机制和函数一样 2)不一样的地方时,变量调用方法时,该变量本身也会作为一个参数传递到方法(如果变量是值类型,则进行值拷贝,如果变量是引用类型,则进行地质拷贝) **方法的声明(定义)** ``` func(receviertype)methodName(参数列表)(返回值列表){ 方法体 return返回值 } 1)参数列表:表示方法输入 2)receviertype:表示这个方法和type这个类型进行绑定,或者说该方法作用于type类型 3)receivertype:type可以是结构体,也可以其它的自定义类型 4)receiver:就是type类型的一个变量(实例),比如:Person结构体的一个变量(实例) 5)返回值列表:表示返回的值,可以多个 6)方法主体:表示为了实现某一功能代码块 7)return语句不是必须的。 ``` **方法的注意事项和细节** 1)结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式 2)如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理 ![](https://img.kancloud.cn/19/a5/19a50e719e541c6814236c6fd73ca20c_884x390.png) 3)Golang中的方法作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct,比如int,float32等都可以有方法 ![](https://img.kancloud.cn/14/5f/145fc46bd60f15d803976bd0e30f9171_851x467.png) 4)方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问。\[讲解\] 5)如果一个类型实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出 ![](https://img.kancloud.cn/8a/7b/8a7b62d026d73a25d452c59cd0d1df98_756x543.png) **方法和函数区别** 1)调用方式不一样 函数的调用方式:函数名(实参列表) 方法的调用方式:变量.方法名(实参列表) 2)对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然 ![](https://img.kancloud.cn/d4/4e/d44e16eff9a195a8609bce3b805cf1a9_939x738.png) 3)对于方法(如struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以 ![](https://img.kancloud.cn/4f/8d/4f8d0f0a284d328df81962e8a48cf9f2_929x343.png) ![](https://img.kancloud.cn/a7/51/a7514473bc5aa68213307d250f0f4602_882x326.png) 1)不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和哪个类型绑定. 2)如果是和值类型,比如(pPerson),则是值拷贝,如果和指针类型,比如是(p\*Person)则是地址拷贝。 **创建结构体变量时指定字段值** 方式1 ![](https://img.kancloud.cn/d0/7d/d07d366136f8baceb10cda418e24cc07_768x600.png) 方式2 ![](https://img.kancloud.cn/76/de/76de5295b4bdf15df1a1c3e9262c38c7_792x346.png)