go基础之结构体

Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。

相对于其他编程语言来说,go语言仅支持封装,不支持继承和多态

结构体的创建

结构体定义

在 Golang 中最常用的方法是使用关键字 type 和 struct 来定义一个结构体,以关键字 type 开始,之后是新类型的名字,最后是关键字 struct

type 类型名 struct { 字段名 字段类型 字段名 字段类型 … } // Person 为用户定义的一个类型 type Person struct { Name string Age int Email string }

其中:

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

还有一些简单的写法

type T struct { a, b int }

它更适用于简单的结构体。

结构体里的字段都有名字,比如上面例子中的 Name、Age 和 Email 等等。如果一个字段在代码中从来不会被用到,那可以把它命名为 _,即空标识符。

声明结构体类型的变量

一旦定义了结构体类型就可以使用这个类型创建值。

使用结构类型声明变量,并初始化为零值

var nick Person

使用结构体字面量声明变量,并初始化为非零值

如果希望变量被初始化为某个非零值,可以通过结构体字面量和短变量声明操作符(:=)来创建变量

// 声明 Person 类型的变量,并初始化所有字段 nick := Person{ Name: "nick", Age: 28, Email: "nickli@xxx.com", }

自定义类型

在Go语言中有一些基本的数据类型,如string、整型、浮点型、布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型。

自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct定义。例如:

//将MyInt定义为int类型 type MyInt int

通过type关键字的定义,MyInt就是一种新的类型,它具有int的特性。

结构体实例化

只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。

结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型。

var 结构体实例 结构体类型

我们通过.来访问结构体的字段(成员变量)

匿名结构体

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

package main import "fmt" func main() { var user struct{Name string; Age int} user.Name = "小明" user.Age = 20 fmt.Printf("%#v\n", user) }

结构体可以包含一个或多个匿名(或者称为内嵌)字段,即这些字段没有显式的名字。仅指明字段的类型,此时该类型就是字段的名字。匿名字段本身可以是一个结构体类型,即结构体可以包含内嵌的结构体。

匿名字段

匿名字段和面向对象编程中的继承概念相似,可以被用来模拟类似继承的行为。Golang 中的基础就是通过内嵌或组合来实现的,所以说在 Golang 中组合比继承更受欢迎。比如下面的例子:

type test struct { name string age int int // 匿名字段 }

内嵌结构体

结构体也是一种数据类型,所以它同样可以作为匿名字段使用:

type Person struct { Name string Age int Email string } type Student struct { Person StudentID int }

下面的代码可以声明并初始化 Student 类型的变量:

st := Student { Person: Person{"jack", 22, "jack@xxx.com"}, StudentID: 1000, }

从这个示例可以看出,内层结构体被简单地插入或者内嵌进外层结构体。这种简单的 "继承" 机制使得 Golang 很轻松就能实现从一个或一些类型中继承部分或全部的实现。

结构体初始化

没有初始化的结构体,其成员变量都是对应其类型的零值

使用键值对初始化

使用键值对对结构体进行初始化时,键对应结构体的字段,值对应该字段的初始值。

p5 := person{ name: "小王子", city: "北京", age: 18, } fmt.Printf("p5=%#v\n", p5) //p5=main.person{name:"小王子", city:"北京", age:18}

也可以对结构体指针进行键值对初始化

当某些字段没有初始值的时候,该字段可以不写。此时,没有指定初始值的字段的值就是该字段类型的零值。

使用值的列表初始化

初始化结构体的时候可以简写,也就是初始化的时候不写键,直接写值

使用这种格式初始化时,需要注意:

  1. 必须初始化结构体的所有字段。
  2. 初始值的填充顺序必须与字段在结构体中的声明顺序一致。
  3. 该方式不能和键值初始化方式混用。

结构体内存布局

结构体占用一块连续的内存。

type test struct { a int8 b int8 } n := test{ 1, 2, } fmt.Printf("n.a %p\n", &n.a) fmt.Printf("n.b %p\n", &n.b)

空结构体

空结构体不占用空间

var v struct{} fmt.Println(unsafe.Sizeof(v)) // 0

构造函数

Go语言的结构体没有构造函数,我们可以自己实现。 例如,下方的代码就实现了一个

person的构造函数。 因为

struct是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以该构造函数返回的是结构体指针类型。

func Person(name String, age int) *person { return &person{ name: name, age: age, } }

调用构造函数

p := Person("小明", 19) fmt.Printf("%#v\n", p)

方法和接受者

Go语言中的

方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self。

方法的定义格式如下:

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) { 函数体 }

其中,

  • 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名称首字母的小写,而不是self、this之类的命名。例如,Person类型的接收者变量应该命名为 p,Connector类型的接收者变量应该命名为c等。
  • 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。
  • 方法名、参数列表、返回参数:具体格式与函数定义相同。

指针类型的接受者

指针类型的接收者由一个结构体的指针组成,由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。这种方式就十分接近于其他语言中面向对象中的this或者self。

条件:

  1. 需要修改接收者中的值
  2. 接收者是拷贝代价比较大的大对象
  3. 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

值类型的接受者

当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值