Go语言面向对象编程

文章目录

银行ATM的例子

相较于面向过程,面向对象有以下优势:

  1. 容易命名
  • 在面向对象中,方法名相同但属于不同的类,这不会引起冲突 ,因为每个类定义了自己的方法和属性。相比之下,函数式编程中的函数名必须唯一,否则会导致冲突。
  1. 代码管理方便
  • 易于模块化开发 。类中包含方法和属性,属性用来记录数据,方法表示行为,类实例化后为对象,行为和数据由对象来统一管理。写出来的代码方法与属性各归各类,代码逻辑清晰,利于扩展;函数也表示行为,但是与函数配合的数据却散落摆放,缺乏"类"这样的结构来统一管理。
  1. 重用性高
  • 代码冗余量小、重用性高。面向对象的代码在使用时,通过调用各个对象中的方法和属性,不同的排列组合就能适应各种不同的业务场景。

Go语言面向对象

  • 在其他编程语言中大多使用class关键字来定义封装对象,表示该类的具体特征,然而Go并不是一个纯面向对象的编程语言 。在Go语言中的面向对象,采用更灵活的结构体替代了类。
  • Go语言并没有提供类class,但是它提供了结构体struct ,方法method,可以在结构体上添加。提供了捆绑数据和方法的行为,这些数据和方法与类相似。
  • Go语言设计的非常简洁优雅,Go没有沿袭传统面向对象编程中的诸多概念,例如继承、虚方法、构造方法和析构方法等。
  • 虽然Go语言没有继承和多态。但是Go语言可以通过匿名字段实现继承,通过接口实现多态。在Go语言中学习面向对象,主要学习结构体struct、方法method、接口interface。

一、结构体定义

结构体定义

  • Go语言中没有"类"的概念,通过struct来实现面向对象
  • 通常用于表达一个事物的全部或部分属性
  • 一种自定义数据类型,可以封装多个基本数据类型
  • 本质是将零个 或者多个任意类型的命名变量组合在一起的聚合数据类型
  • 每个变量叫做结构体的成员,变量名必须唯一,可用"_"补位
  • 支持使用自身指针类型成员

结构体语法格式

go 复制代码
type 类型名 struct {
 字段名 字段类型
 字段名 字段类型
 ......
}

语法

  • 类型名:标识自定义结构体的名称,在同一个包内不能重复。
  • 字段名:表示结构体字段名,结构体中的字段名必须唯一。
  • 字段类型:表示结构体字段的具体类型。

案例

go 复制代码
 type Student struct {
        stuID int
        stuName string
        age int
    }//成员变量通常一行写一个,变量的名称在类型的前面
go 复制代码
 type Student struct {
        stuID,age int
        stuName string
}//相同类型的连续成员变量可以写在一行上。

示例1

go 复制代码
 type Student1 struct {
        stuId,age int
        stuName,address string
        class,teacher string
    }

示例2

go 复制代码
 type Student2 struct {
        stuId int
        address,stuName string
        age int
        class,teacher string
    }
  • 成员变量的顺序对于结构体同一性很重要
  • 相同类型的不连续成员变量不可以写在一行上

二、实例化结构体

结构体的使用

  • 结构体属于数据类型 ,因此和声明Go语言内置数据类型一样使用var关键字声明结构体类型
  • 只有当结构体实例化时,才会真正地分配内存
  • 必须实例化后才能使用结构体的字段

结构体实例化语法

go 复制代码
var 结构体实例 结构体类型

示例:

go 复制代码
package main
import "fmt"
func main()  {
    type person struct {
        name string
        city string
        age  int8
    }
    var p1 person	//实例化结构体
}

在定义一些临时数据结构等场景下还可以使用匿名结构体

go 复制代码
package main
import "fmt"
func main()  {
    var p1 struct{name string;city string; age int}
}

new关键字

go 复制代码
结构体实例 := new(结构体类型)
  • 使用new关键字 实例化结构体后,得到的是结构体的地址;结构体类型为指针类型,但结构体本身仍然是值类型
  • 通过&符号对结构体取地址
  • 取地址的同时会将结构体实例化
go 复制代码
package main
import "fmt"
func main()  {
    type person struct {
        name string
        city string
        age  int8
    }
    var p1 =new(person)
    //p1 := &person{}//相当于这样定义
}

三、初始化结构体变量

结构体初始化

  • 结构体类型的值可以通过结构体字面量来设置,即通过结构体的成员变量来设置
  • 有两种格式的结构体字面量:顺序初始化、指定成员初始化

顺序初始化

  • 要求顺序为每个成员变量指定一个值,这种格式必须记住每个成员变量的顺序

指定初始化

  • 通过指定部分或者全部成员变量的名称和值来初始化结构体变量,如果成员被忽略的话将默认用零值
go 复制代码
package main
import (
	"fmt"
)
func main()  {
    type person struct {
        name string
        city string
        age  int8
    }
 //顺序初始化,每个成员必须初始化
    var p1 person
    p1.name = "Go语言"
    p1.city = "深圳"
    p1.age = 18
    fmt.Println(p1)
    //指定成员初始化,没有初始化的成员自动赋值为零
    p2 := person{name: "Golang"}
    fmt.Println(p2)
}


//运行结果为:
//{Go语言 深圳 18}
//{Golang  0}

四、匿名结构体

匿名结构体定义

  • 匿名结构体,顾名思义,即没有名字的结构体,与匿名函数类似
  • 匿名结构体无须type关键字 就可以直接使用,匿名结构体在创建的同时也要创建对象
  • 匿名结构体的初始化和使用更加简单,无须通过type关键字定义,且不用写出类型名称

匿名结构体语法格式

go 复制代码
结构体实例 := struct{
	//匿名结构体定义
	成员变量1 类型1
	成员变量2 类型2
	...
}{
  	//成员变量初始化(可选)
	成员变量1:值1, 
	成员变量2:值2, 
	...
}

示例:

go 复制代码
attribute2 := struct {
	Title, Publisher string
	Price            float64
	BookId           uint
	Discount         string
}{
	"唐宋传奇选",
	"人民文学出版社",
	15.1,
	566357,
	"6折",
}

五、结构体内嵌

结构体内嵌语法、特性

语法:

go 复制代码
type 结构体1 struct{
    字段名1  字段类型1
    字段名2  字段类型2
}
type 结构体2 struct{
    结构体1
    字段名3  字段类型3
}

特性:

  • 是一种组合特性
  • 使用结构体内嵌可构建一种面向对象编程思想中的继承关系
  • 结构体实例化后,可直接访问内嵌结构体的所有成员变量和方法

示例:

go 复制代码
//定义关于圆心坐标、圆、圆柱的结构体:
type Point struct {
    x,y int
}
type Circle struct {
    x,y,r int
}
type Cylinder struct {
    x,y,r,h int
}


//嵌入相同部分:
type Point struct {
    x,y int
}
type Circle struct {
    P Point
    r int
}
type Cylinder struct {
    C Circle
    h int
}

键值对形式

go 复制代码
type 结构体1 struct{
    字段名1  字段类型1
    字段名2  字段类型2
}
type 结构体2 struct{
    结构体1
    字段名3  字段类型3
}


func main(){
    结构体实例 := 结构体2 {
        结构体1{
            字段名1:字段名1值
            字段名2:字段名2值
        },
        字段名3:字段名3值
    }
}
  • 键值对之间以逗号分割
  • 键值之间以冒号分割
  • 结构体成员的字段名应该具有唯一性

示例:

go 复制代码
package main
import "fmt"
type rectangle struct {
    length,wide int
}
type cuboid struct {
    r rectangle
    high int
}


func main(){
    c :=cuboid{
        r:rectangle{
            length: 5,
            wide: 6,
        },
        high:7,
    }
    fmt.Println(c.r.length)
    fmt.Println(c.r.wide)
    fmt.Println(c.high)
}


//运行结果为:
//5
//6
//7

当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找,但嵌套结构体内部可能存在相同的字段名。

这个时候为了避免歧义需要指定具体的内嵌结构体的字段。

go 复制代码
package main
import "fmt"
type Address struct {
	City    string
	Country string   }
type ContactInfo struct {
	Phone string
         City  string    }
type Person struct {
	Name    string
	Address     // 匿名嵌套
	ContactInfo // 匿名嵌套
}
func main(){
   p := Person{
Name: "Alice",
Address: Address{
City:    "New York",
Country: "USA",     },
ContactInfo: ContactInfo{
Phone: "123-456-7890",
City:  "Los Angeles",
},   }   
fmt.Println("Person Name:", p.Name)
fmt.Println("Address City:", p.Address.City)}
fmt.Println("ContactInfo City:", p.ContactInfo.City)

当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找,但嵌套结构体内部可能存在相同的字段名。

这个时候为了避免歧义需要指定具体的内嵌结构体的字段。

多值列表形式

go 复制代码
type 结构体1 struct{
    字段名1  字段类型1
    字段名2  字段类型2
}
type 结构体2 struct{
    结构体1
    字段名3  字段类型3
}
func main(){
    结构体实例 := 结构体2 {
        结构体1{
            字段名1值
            字段名2值
        },
        字段名3值
    }
}

!必须初始化结构体所有字段 每一个初始值的填充顺序必须与字段在结构体中的声明顺序一致 键值对与多值列表的初始化形式不能混用

示例:

go 复制代码
package main
import "fmt"
type rectangle struct {
    length,wide int
}
type cuboid struct {
    r rectangle
    high int
}
func main(){
    c :=cuboid{
        rectangle{
            5,
            6,
        },
        7,
    }
    fmt.Println(c.r.length)
    fmt.Println(c.r.wide)
    fmt.Println(c.high)
}


//运行结果为:
//5
//6
//7

通过嵌套匿名结构体实现继承

go 复制代码
package main
import "fmt"
//Animal 动物
type Animal struct {
    name string
}
func (a *Animal) move() {
    fmt.Printf("%s会动!\n", a.name)
}
//Dog 狗
type Dog struct {
    Feet    int8
    *Animal //通过嵌套匿名结构体实现继承
}
func (d *Dog) wang() {
    fmt.Printf("%s会汪汪汪~\n", d.name)
}
func main() {
    d1 := &Dog{
        Feet: 4,
      Animal: &Animal{  //注意嵌套的是结构体指针
            name: "乐乐",
        },
    }
    d1.wang()
    d1.move()
}



//运行结果为:
//乐乐会汪汪汪~
//乐乐会动!
相关推荐
----云烟----32 分钟前
QT中QString类的各种使用
开发语言·qt
lsx20240636 分钟前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic1 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it1 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康1 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神2 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
宅小海2 小时前
scala String
大数据·开发语言·scala
qq_327342732 小时前
Java实现离线身份证号码OCR识别
java·开发语言
锅包肉的九珍2 小时前
Scala的Array数组
开发语言·后端·scala
心仪悦悦2 小时前
Scala的Array(2)
开发语言·后端·scala