首页 > 其他分享 >golang快速入门:结构体

golang快速入门:结构体

时间:2023-12-19 19:06:54浏览次数:32  
标签:入门 animal 方法 fmt cat golang Animal Println 快速

结构体

Go 语言的面向对象编程与我们之前所熟悉的 PHP、Java 那一套完全不同,没有 classextendsimplements 之类的关键字和相应的概念,而是借助结构体来实现类的声明。

type Person struct {
    name string //名字
    male bool   //性别
}

可以理解为类名 Person,并且包含了 namemale 两个属性。

可以通过定义形如 NewXXX 这样的全局函数(首字母大写)作为结构体的初始化函数:

func NewPerson(name string, male bool) *Persion {
    return &Person{name, male}
}


person := NewPerson("结构体", false)
fmt.Println(person)

成员方法

值方法

要为 Go 结构体定义成员方法,需要在 func 和方法名之间声明方法所属的结构体(有的地方将其称之为接收者声明),以 Person 结构体为例,要为其定义获取 name 值的方法,可以这么做:

func (s Person) GetName() string  {
    return s.name
}

可以在初始化 Person 结构体后,通过 GetName() 方法获取 name 值:

person := NewPerson("结构体", false)
fmt.Println("Name:", person.GetName())

通过在函数中增加接收者声明的方式定义了函数所归属的类型,这个时候,函数就不再是普通的函数,而是类的成员方法了。

指针方法

如果需要在函数内部修改成员变量的值,并且该修改要作用到该函数作用域以外,那么就需要传入指针类型(结构体是值类型,不是引用类型,所以需要显式传入指针)。在 GetName 方法中,由于不需要对类的成员变量进行修改,所以不需要传入指针。

func (s *P) SetName(name string) {
    s.name = name
}

初始化 Person 结构体之后,通过 SetName 方法修改 name 值,然后再通过 GetName 将其打印出来:

person := NewPerson("结构体", false)
person.SetName("结构体测试")
fmt.Println("Name:", person.GetName())

接收者类型为指针的成员方法叫做指针方法,接收者类型为非指针的成员方法叫做值方法。

值方法和指针方法的区别

在 Go 语言中,当我们将成员方法 SetName 所属的类型声明为指针类型时,严格来说,该方法并不属于 Person 结构体,而是属于指向 Person 的指针类型。

当我们有如下情形的考量时,需要将成员方法定义为指针方法:

  1. 数据一致性:方法需要修改传入的类型实例本身;
  2. 方法执行效率:如果是值方法,在方法调用时一定会产生值拷贝,而大对象拷贝代价很大。

通过组合实现结构体的继承和方法重写

继承

Go 没有直接提供继承相关的语法实现,但是我们通过组合的方式间接实现类似功能,所谓组合,就是将一个结构体型嵌入到另一个结构体,从而构建新的结构体。

现在有一个 Animal 结构体类型,它有一个属性 Name 用于表示该动物的名称,以及三个成员方法。

type Animal struct {
    Name string
}

func (a Animal) Call() string {
    return "动物的叫声..."
}

func (a Animal) FavorFood() string {
    return "爱吃的食物..."
}

func (a Animal) GetName() string  {
    return a.Name
}

定义一个继承自该类型的子结构体 Cat

type Cat struct {
    Animal
}

在 Cat 结构体类型中,嵌入了 Animal ,可以在 Cat 实例上访问所有 Animal 类型包含的属性和方法:

func main() {
    animal := Animal{"布偶猫"}
    cat := Cat{animal}

    fmt.Println(cat.GetName())
    fmt.Println(cat.Call())
    fmt.Println(cat.FavorFood())
}

通过组合实现了结构体与结构体之间的继承功能。

方法重写

通过在子结构体中定义同名方法来覆盖父类方法的实现,在面向对象编程中这一术语叫做方法重写,比如 Cat 结构体中,可以重写 Call 方法和 FavorFood 方法的实现如下:

func (c Cat) FavorFood() string {
    return "鱼和老鼠"
}

func (c Cat) Call() string {
    return "喵喵喵"
}


animal := Animal{"布偶猫"}
cat := Cat{animal}

fmt.Print(cat.Animal.Call())
fmt.Println(cat.Call())
fmt.Print(cat.Animal.FavorFood())
fmt.Println(cat.FavorFood())

组合的实现方式更加灵活,不用考虑单继承还是多继承,想要继承哪个类型的方法,直接组合进来就可以了。

继承指针类型的属性和方法

在 Go 语言中,还可以通过指针方式继承某个类型的属性和方法:

type Cat struct { 
    *Animal
}

在调用时,传入 Animal 实例的指针引用就可以了

func main() {
    animal := Animal{"布偶猫"}
    cat := Cat{&animal}

    fmt.Println(cat.Animal.GetName())
    fmt.Print(cat.Animal.Call())
    fmt.Println(cat.Call())
    fmt.Print(cat.Animal.FavorFood())
    fmt.Println(cat.FavorFood())
}

当我们通过组合实现结构体之间的继承时,由于结构体实例本身是值类型,如果传入值字面量的话,实际上传入的是结构体实例的副本,对内存耗费更大,所以组合指针类型性能更好。

为组合类型设置别名

type Cat struct {
    animal *Animal
}

...

func main() {
    animal := Animal{"布偶猫"}
    cat := Cat{&animal}

   // 通过 animal 引用 Animal 类型实例 
    fmt.Println(cat.animal.GetName())
    fmt.Print(cat.animal.Call())
    fmt.Println(cat.Call())
    fmt.Print(cat.animal.FavorFood())
    fmt.Println(cat.FavorFood())
}

结构体属性和方法的可见性

在 Go 语言中,无论是变量、函数还是结构体属性和成员方法,可见性都是以包为维度的。Go 语言没有提供privateprotected 和 public关键字。可见性都是根据其首字母的大小写来决定的,如果变量名、属性名、函数名或方法名首字母大写,就可以在包外直接访问,否则只能在包内访问。

标签:入门,animal,方法,fmt,cat,golang,Animal,Println,快速
From: https://blog.51cto.com/u_14681786/8891854

相关文章

  • Java Properties配置文件使用方法入门详解​
    JavaProperties配置文件使用方法详解使用配置文件的优点:好处1:可以把软件的设置永久化存储好处2:如果我们要修改参数,不需要改动代码,直接修改配置文件就可以了Properties配置文件文件后缀名为.properties,其内容是按键值对存储的。前面为键,后面为值。properties是一个双列集合,拥有Ma......
  • kettle从入门到精通 第二十四课 kettle 部署生产常用命令
    一、设置KETTLE_HOME环境变量 假设kettle软件目录为/xxx/data-integrationvi~/.bash_profileexportKETTLE_HOME=/xxx/data-integration/configsource~/.bash_profileecho$KETTLE_HOME二、启动carte命令1、cd/xxx/data-integration./carte.sh./pw......
  • IDE之VS:Visual Studio的简介(包括 VS2013、VS2015、VS2017、VS2019、VS2022)、安装、
    原文链接:https://blog.csdn.net/qq_41185868/article/details/81052119最近开始使用vs2019,应该是最新的版本。之前都是vs2015,感觉19更智能,兼容性更好,速度也更快。详细了解下这几个版本。1、简介:MicrosoftVisualStudio(简称VS)是美国微软公司的开发工具包系列产品,功能完备的I......
  • RISC-V系列单片机快速入门指南
     如何获取芯片开发资料方法一:按型号选择我们更推荐采用按型号选择的方法,获取所对应型号芯片的开发资料,这能有效降低错误使用资料的风险!沁恒官网首页的产品中心,点击青稞RISC-V通用系列,可跳转至CH32V系列单片机的产品选型表。 以CH32V203C8T6为例,点击红色方框中的芯......
  • MapReduce入门案例——wordcount词频统计分析
        说实话,wordcount这个案例挺土的,但是作为入门案例,还是值得学习的,本篇就通过MapReduce来对词频进行一个统计分析,并写出核心代码。一:案例介绍:     Input:读取文本文件;Splitting:将文件按照文件块(block)或者行进行拆分,此时得到的K1为偏移量,V1表示对应行......
  • Linux服务器快速安装FastGPT知识库问答系统
    最近开始体验FastGPT知识库问答系统,参考官方文档,在自己的阿里云服务器使用DockerCompose快速完成了部署。环境说明:阿里云ECS,2核8G,X86架构,CentOS7.9操作系统。Docker与Docker-Compose安装1.登录服务器,执行相关命令完成安装。#安装Dockercurl-fsSLhttps://get.docker.co......
  • Kernel Memory 入门系列: Embedding 简介
    KernelMemory入门系列:Embedding简介在RAG模式其实留了一个问题。我们对于的用户问题的理解和文档的检索并没有提供合适的方法。当然我们可以通过相对比较传统的方法。例如对用户的问题进行关键词提取,然后通过关键词检索文档。这样的话,就需要我们提前对文档做好相关关键......
  • MySQL主从搭建入门
    MySQL主从搭建入门原创 代码新手 代码新手 2023-10-2817:32 发表于上海MySQL之间数据复制的基础是二进制日志文件(binarylogfile)。一台MySQL数据库一旦启用二进制日志后,其作为master,它的数据库中所有操作都会以“事件”的方式记录在二进制日志中,其他数据库作为slave......
  • Eolink Apikit 快速发起 API 测试,一键生成测试数据
    我们在测试接口时,通常需要先创建API文档,再根据API文档生成测试用例。未创建该接口文档,仅临时调试接口,EolinkApikit支持创建API快速测试页面,输入接口相关的信息即可进行快速测试。EolinkApikit支持操作数据库,API测试时,可以一键生成测试请求数据。这可以减少数据输入步......
  • MySQL入门
    ps:(文中的中括号表示可以添加或者不添加)初始操作:  自己创建了数据库,展示时是这样的,但是在每一个数据库名字之下,可以想象又是一张这种表格,与一层层打开文件夹相似;如下:列类型:以上图中lesson数据库中红色表格为例:每个表格中的一列都可能对应不同类型;eg:姓名那一列放置的就是......