【go基础】结构体

文章详细介绍了Golang中结构体的作用,包括数据组织、面向对象特性、内存布局控制以及在JSON序列化中的应用。同时,讨论了Golang的面向对象编程特点,如基于结构体而非类实现OOP,并通过接口实现多态。还阐述了结构体变量的声明和使用,以及结构体字段的访问和注意事项。
摘要由CSDN通过智能技术生成

为什么引入结构体?

在Go语言中,引入结构体(struct)是为了更灵活地组织和操作数据。结构体是一种自定义的复合数据类型,可以包含不同类型的字段(成员变量),用于描述一个具体的实体或对象。

  • 数据组织:结构体允许将多个相关的数据字段组织在一起,形成一个逻辑上的单元。通过定义结构体,可以将相关的数据封装在一起,提高代码的可读性和可维护性。
  • 类似对象的概念:结构体可以用来表示对象的状态和行为。通过在结构体中定义字段和方法,可以实现一些面向对象的特性,如封装、继承和多态。
  • 数据传递:结构体可以作为函数的参数和返回值,方便地传递复杂的数据结构。通过传递结构体,可以将相关的数据打包成一个单独的实参,简化函数的调用和处理逻辑。
  • 内存布局控制:结构体允许精确地控制内存布局,包括字段的对齐、填充和内存对齐等。这在与外部系统进行数据交互、网络通信和数据持久化等方面非常有用。
  • 可扩展性:结构体可以通过嵌套其他结构体或使用指针来实现复杂的数据结构。这使得可以创建具有层次结构和递归特性的数据类型,满足不同业务需求。
  • JSON和XML序列化:结构体对于JSON和XML等数据序列化和反序列化操作非常友好。通过为结构体添加标签(tag),可以控制序列化和反序列化过程中的字段名称、格式和映射等。

总体而言,结构体提供了一种组织和操作数据的方式,更加灵活和可扩展。结构体在Go语言中被广泛应用于各种场景,包括定义自定义数据类型、创建数据模型、表示实体对象等。

Golang 语言面向对象编程说明

  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 中面向接口编程是非常重要的特性。

结构体

  1. 结构体是自定义的数据类型,代表一类事物.
  2. 结构体变量(实例)是具体的,实际的,代表一个具体变量
//定义一个Cat结构体,将Cat的各个字段/属性信息,放入到Cat结构体进行管理
type Cat struct {
	Name string 
	Age int 
	Color string 
	Hobby string
	Scores [3]int // 字段是数组...
}

结构体声明

type 结构体名称 struct { 
	field1 type
	field2 type
}

例如

type Person struct {
  name string
  age int
}

创建结构体变量

  1. var定义
var person Person

定义了一个名为person的Person结构体;

  1. 推导定义(定义的同时初始化)
p2 := Person{"mary", 20}
	// p2.Name = "mary"
	// p2.Age = 20
	fmt.Println(p2)
  1. & : var person *Person = new (Person)
var p3 *Person= new(Person)
	//因为p3是一个指针,因此标准的给字段赋值方式
	//(*p3).Name = "smith" 也可以这样写 p3.Name = "smith"

	//原因: go的设计者 为了程序员使用方便,底层会对 p3.Name = "smith" 进行处理
	//会给 p3 加上 取值运算 (*p3).Name = "smith"
	(*p3).Name = "smith" 
	p3.Name = "john" 

	(*p3).Age = 30
	p3.Age = 100
	fmt.Println(*p3)
  1. 案例: var person *Person = &Person{}
	//案例: var person *Person = &Person{}

	//下面的语句,也可以直接给字符赋值
	//var person *Person = &Person{"mary", 60} 
	var person *Person = &Person{}

	//因为person 是一个指针,因此标准的访问字段的方法
	// (*person).Name = "scott"
	// go的设计者为了程序员使用方便,也可以 person.Name = "scott"
	// 原因和上面一样,底层会对 person.Name = "scott" 进行处理, 会加上 (*person)
	(*person).Name = "scott"
	person.Name = "scott~~"

	(*person).Age = 88
	person.Age = 10
	fmt.Println(*person)

第 3 种和第 4 种方式返回的是 结构体指针
结构体指针访问字段的标准方式应该是:(*结构体指针).字段名 ,比如 (*person).Name = “tom”,但 go 做了一个简化,也支持 结构体指针.字段名, 比如 person.Name = “tom”。更加符合程序员使用的习惯,go 编译器底层 对 person.Name 做了转化 (*person).Name。

结构体字段

  • 从概念或叫法上看: 结构体字段 = 属性 = field (即授课中,统一叫字段)
  • 字段是结构体的一个组成部分,一般是基本数据类型、数组,也可是引用类型
  • 字段声明语法同变量,示例:字段名 字段类型
  • 字段的类型可以为:基本类型、数组或引用类型
  • 在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值(默认值) :
    布尔类型是 false ,数值是 0 ,字符串是 “”。
    数组类型的默认值和它的元素类型相关,比如 score [3]int 则为[0, 0, 0]
    指针,slice,和 map 的零值都是 nil ,即还没有分配空间。
package main
import (
	"fmt"
)

//如果结构体的字段类型是: 指针,slice,和map的零值都是 nil ,即还没有分配空间
//如果需要使用这样的字段,需要先make,才能使用.

type Person struct{
	Name string
	Age int
	Scores [5]float64
	ptr *int //指针 
	slice []int //切片
	map1 map[string]string //map
}

func main() {
	//定义结构体变量
	var p1 Person
	fmt.Println(p1)
	//{ 0 [0 0 0 0 0] <nil> [] map[]}

	if p1.ptr == nil {
		fmt.Println("ok1")
	}
	//ok1            
	
	if p1.slice == nil {
		fmt.Println("ok2")
	} 
	//ok2      

	if p1.map1 == nil {
		fmt.Println("ok3")
	}
	//ok3                                                          

	//使用slice, 再次说明,一定要make
	p1.slice = make([]int, 10)
	p1.slice[0] = 100 //ok

	//使用map, 一定要先make
	p1.map1 = make(map[string]string)
	p1.map1["key1"] = "tom~" 
	fmt.Println(p1)
	//{ 0 [0 0 0 0 0] <nil> [100 0 0 0 0 0 0 0 0 0] map[key1:tom~]}
}
  • 不同结构体变量的字段是独立,互不影响,一个结构体变量字段的更改,不影响另外一个, 结构体是值类型。
//不同结构体变量的字段是独立,互不影响,一个结构体变量字段的更改,
	//不影响另外一个, 结构体是值类型
	var monster1 Monster
	monster1.Name = "牛魔王"
	monster1.Age = 500

	monster2 := monster1 //结构体是值类型,默认为值拷贝
	monster2.Name = "青牛精"

	fmt.Println("monster1=", monster1) //monster1= {牛魔王 500}
	fmt.Println("monster2=", monster2) //monster2= {青牛精 500}

结构体类型的内存访问机制

在这里插入图片描述

结构体使用注意事项和细节

  1. 结构体的所有字段在内存中是连续的
  2. 结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类
    型)
  3. 结构体进行 type 重新定义(相当于取别名),Golang 认为是新的数据类型,但是相互间可以强转
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值