Go 结构体的使用

结构体是用户定义的类型,表示若干个字段(Field)的集合。有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体。

例如,一个职员有 firstNamelastName 和 age 三个属性,而把这些属性组合在一个结构体 employee 中就很合理。

结构体的声明基础

type Employee struct {
    firstName string
    lastName  string
    age       int
}

 在上面的代码片段里,声明了一个结构体类型 Employee,它有 firstNamelastName 和 age 三个字段。通过把相同类型的字段声明在同一行,结构体可以变得更加紧凑。在上面的结构体中,firstName 和 lastName 属于相同的 string 类型,于是这个结构体可以重写为: 

type Employee struct {
    firstName, lastName string
    age, salary         int
}

上面的结构体 Employee 称为 命名的结构体(Named Structure)。我们创建了名为 Employee 的新类型,而它可以用于创建 Employee 类型的结构体变量。

声明结构体时也可以不用声明一个新类型,这样的结构体类型称为 匿名结构体(Anonymous Structure)。

var employee struct {
    firstName, lastName string
    age int
}

上述代码片段创建一个匿名结构体 employee 。  

  emp3 := struct {
        firstName, lastName string
        age, salary         int
    }{
        firstName: "Andreah",
        lastName:  "Nikola",
        age:       31,
        salary:    5000,
    }

 上述代码片段通过匿名结构体 创建了一个结构体变量 。 

结构体基础使用

  • 结构体变量初始化
  • 结构体指针变量初始化
  • 结构体变量之间的比较与赋值
  • 在函数中传递结构体变量与结构体指针变量
  • 定义结构体函数成员与调用
package main

import (
	"fmt"
)
//结构体为类型定义
//创建一个结构体,四个数据属性,四个函数属性
/////////////////////////////////////
type Person struct {
		name string
		age int
		sex bool
		//hobby []string
}

//*Person意味传递是真实地址
func (p *Person)Eat(){
	fmt.Printf("%s爱吃西红柿炒鸡蛋\n",p.name)
}
func (p *Person)Drink(){
	fmt.Printf("%s爱喝可乐\n",p.name)
}
func (p *Person)Sleep(){
	fmt.Printf("%s要睡8个小时\n",p.name)
}
func (p *Person)Love(){
	fmt.Printf("%s喜欢\n",p.name)
}
////////////////////////////////////////////

//值传递与属性传递
////////////////////////
func MakeHimLove(p Person){p.Love()}

func MakeHisPtrLove(p *Person){p.Love()}
/////////////////////

func main(){

//////结构体变量初始化///////////////
	//顺序初始化:创建对象时按顺序给所有属性赋值
	p1 := Person{"lili",8,true}
	fmt.Println(p1)
	//指定成员初始化:指定成员变量进行赋值,没有指定的成员变量为默认值
	p2 := Person{name:"mingming",sex:true} //--未初始化的成员变量,取该数据类型的默认值。
	fmt.Println(p2)
	//创建后初始化:
	p3 := Person{} //--未初始化的成员变量,取该数据类型的默认值。
	p3.name ="xiaoli"
	p3.age =19
	fmt.Println(p3)
////////////////////////

///////////结构体指针变量初始化/////////////

	//一般初始化
	var p4 *Person = &Person{"weiai",26,true}
	fmt.Println(p4)

	//使用new初始化
	p5 := new(Person)
	p5.name ="titi"
	p5.age =31
	p5.sex =false
	//注意:在64位操作系统下,所有类型的指针,均为8个字节
////////////////////////

///////////结构体变量的比较和赋值/////////////
//1.比较:只能使用 ==和!=   不能使用 > < >=  <=
//注意:结构体有些类型存在,结构体变量是不能进行比较的,如:[]string//结构体是值类型。如果它的每一个字段都是可比较的,则该结构体也是可比较的。如果两个结构体变量的对应字段相等,则这两个变量也是相等的。
	fmt.Println("p1 == p2:",p1 == p2)
//2.赋值:相同类型结构体可以直接赋值
	var temp Person
	temp = p1
	fmt.Println(temp)
////////////////////////

////////////函数内部使用结构体传参/////////////
	//值传递传递的是副本,引用传递传递的才是本身
	//注意:值传递内存消耗大,效率低
	//unasfe.Sizeof(变量名):查看变量所占的内存空间大小
	//要求传递值就必须传递值
	//MakeHimLove(p1)
	//要求传递指针就必须传递指针:地址传递、引用传递
	//结构体变量的地址为结构体首个元素的地址
	//MakeHisPtrLove(&p1)
/////////////////////

////////////结构体调用自身函数//////////////////
	/////////////////////
	//	//实例调用方法
	//	p1.Eat()
	//	p1.Drink()
	//	p1.Sleep()
	//	p1.Love()
/////////////////////////////////////////////

}

  

  

补充知识点

  • 匿名字段
  • 嵌套结构体(Nested Structs)
  • 提升字段(Promoted Fields)
  • 导出结构体和字段

匿名字段

当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段(Anonymous Field)。

以下代码中有 Person 结构体,它含有两个匿名字段 string 和 int

package main

import (
    "fmt"
)
type Person struct {
    string
    int
}

func main() {
    p := Person{"Naveen", 50}
    fmt.Println(p)
}

该程序输出 {Naveen 50}

虽然匿名字段没有名称,但其实匿名字段的名称就默认为它的类型。比如在上面的 Person 结构体里,虽说字段是匿名的,但 Go 默认这些字段名是它们各自的类型。所以 Person 结构体有两个名为 string 和 int 的字段。

 

嵌套结构体(Nested Structs)

结构体的字段有可能也是一个结构体。这样的结构体称为嵌套结构体。

package main

import (
    "fmt"
)

type Address struct {
    city, state string
}
type Person struct {
    name string
    age int
    address Address
}

func main() {
    var p Person
    p.name = "Naveen"
    p.age = 50
    p.address = Address {
        city: "Chicago",
        state: "Illinois",
    }
    fmt.Println("Name:", p.name)
    fmt.Println("Age:",p.age)
    fmt.Println("City:",p.address.city)
    fmt.Println("State:",p.address.state)
}

上面的结构体 Person 有一个字段 address,而 address 也是结构体。该程序输出:

Name: Naveen
Age: 50
City: Chicago
State: Illinois
 

  

提升字段(Promoted Fields)

如果是结构体中有匿名的结构体类型字段,则该匿名结构体里的字段就称为提升字段。这是因为提升字段就像是属于外部结构体一样,可以用外部结构体直接访问。我知道这种定义很复杂,所以我们直接研究下代码来理解吧。

type Address struct {
    city, state string
}
type Person struct {
    name string
    age  int
    Address
}

在上面的代码片段中,Person 结构体有一个匿名字段 Address,而 Address 是一个结构体。现在结构体 Address 有 city 和 state 两个字段,访问这两个字段就像在 Person 里直接声明的一样,因此我们称之为提升字段。

package main

import (
    "fmt"
)

type Address struct {
    city, state string
}
type Person struct {
    name string
    age  int
    Address
}

func main() {
    var p Person
    p.name = "Naveen"
    p.age = 50
    p.Address = Address{
        city:  "Chicago",
        state: "Illinois",
    }
    fmt.Println("Name:", p.name)
    fmt.Println("Age:", p.age)
    fmt.Println("City:", p.city) //city is promoted field
    fmt.Println("State:", p.state) //state is promoted field
}

在上面代码中的第 26 行和第 27 行,我们使用了语法 p.city 和 p.state,访问提升字段 city 和 state 就像它们是在结构体 p 中声明的一样。该程序会输出:

Name: Naveen
Age: 50
City: Chicago
State: Illinois

  

导出结构体和字段

如果结构体名称以大写字母开头,则它是其他包可以访问的导出类型(Exported Type)。同样,如果结构体里的字段首字母大写,它也能被其他包访问到。

让我们使用自定义包,编写一个程序来更好地去理解它。

在你的 Go 工作区的 src 目录中,创建一个名为 structs 的文件夹。另外在 structs 中再创建一个目录 computer

在 computer 目录中,在名为 spec.go 的文件中保存下面的程序。

package computer

type Spec struct { //exported struct
    Maker string //exported field
    model string //unexported field
    Price int //exported field
} 

上面的代码片段中,创建了一个 computer 包,里面有一个导出结构体类型 SpecSpec 有两个导出字段 Maker 和 Price,和一个未导出的字段 model。接下来我们会在 main 包中导入这个包,并使用 Spec 结构体。

package main

import "structs/computer"
import "fmt"

func main() {
    var spec computer.Spec
    spec.Maker = "apple"
    spec.Price = 50000
    fmt.Println("Spec:", spec)
}

包结构如下所示:

src
   structs
        computer
            spec.go
        main.go

在上述程序的第 3 行,我们导入了 computer 包。在第 8 行和第 9 行,我们访问了结构体 Spec 的两个导出字段 Maker 和 Price。执行命令 go install structs 和 workspacepath/bin/structs,运行该程序。

如果我们试图访问未导出的字段 model,编译器会报错。将 main.go 的内容替换为下面的代码。

package main

import "structs/computer"
import "fmt"

func main() {
    var spec computer.Spec
    spec.Maker = "apple"
    spec.Price = 50000
    spec.model = "Mac Mini"
    fmt.Println("Spec:", spec)
}

在上面程序的第 10 行,我们试图访问未导出的字段 model。如果运行这个程序,编译器会产生错误:spec.model undefined (cannot refer to unexported field or method model)

refer:『GCTT 出品』Go 系列教程 —— 第 16 部分:结构体

原文地址:https://www.cnblogs.com/-wenli/p/11783529.html

时间: 2024-10-20 20:05:59

Go 结构体的使用的相关文章

关于结构体

1.结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,叫做结构. typedef struct People { int a; char b; double c; }P: 其中:struct是关键词, People是标签, a b c是成员, P是此结构体声明的变量. 于是在声明变量的时候就可:P p1; 这里的P实际上就是struct People的别名.P==struct People 另外这里也可以不写People(于是也不能struct People p1;了,

Linux C中结构体初始化

    在阅读GNU/Linux内核代码时,我们会遇到一种特殊的结构初始化方式.该方式是某些C教材(如谭二版.K&R二版)中没有介绍过的.这种方式称为指定初始化(designated initializer).下面我们看一个例子,Linux-2.6.x/drivers/usb/storage/usb.c中有这样一个结构体初始化项目: static struct usb_driver usb_storage_driver = { .owner = THIS_MODULE, .name = "

在Swift结构体中如何实现写时复制?

结构体(Struct)在Swift语言中占有重要地位,在Swift标准库中,大约有90%的公开类型都是结构体,包括我们常用的Array.String.Dictionary.结构体相比类,一个最重要的特性就是它是值类型,而类似引用类型.值类型是通过复制值来赋值的,而不是引用同一个内存地址,这样就不存在数据共享的问题,能防止意外的数据改变,并且它是线程安全的. 举一个很简单的例子,在objc中,数组是类,是引用类型,在Swift中,数组是结构体,是值类型.因此下面的代码中: let array1 =

结构体的大小

系统在存储结构体变量时存在地址对齐问题,编译器在编译程序时会遵循两条原则: 一.结构体变量中成员的偏移量必须是成员大小的整数倍: 二.结构体大小必须是所有成员大小的整数倍. 1 #include<stdio.h> 2 3 struct a{ 4 int i; 5 float f; 6 char c; 7 double d; 8 long l; 9 }b; 10 11 int main(){ 12 printf("%d\n",sizeof(b.i));// 4 13 prin

关于OC中直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型

关于OC直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型,我们完全可以把其转换为OC对象来进项打印调试,而不必对结构体中的成员变量进行打印.就好比我们可以使用NSStringFromCGRect(CGRect rect)来直接打印一个结构体,其他打印可以参考以下内容 UIKIT_EXTERN NSString *NSStringFromCGPoint(CGPoint point); UIKIT_EXTERN NSString *NSStringFrom

38-oc常用结构体

常用结构体 在开发中苹果推荐我们使用CG开头的结构体, 也就是说NS开头的结构体一般不用 OC中定义一个点,用什么结构体 NSPoint; CGPoint point = NSMakePoint(10, 20); OC中保存物体尺寸的,用什么结构体 NSSize; CGSize size = NSMakeSize(100, 50); OC中保存某个物体的位置和尺寸,用什么结构体 NSRect; CGRect rect = NSMakeRect(10, 20, 100, 50); NSNumber

结构体在固件库中的应用

上次介绍了一般结构体的定义以及引用方法,那么接下来将对结构体在官方固件库是如何具体使用的做出简单说明. 结构体指针成员变量引用方法是通过“→”符号来实现,比如要访问student1结构体指针指向的结构体的成员变量name,那么方法是: stuednt1—>name; 如在STM32官方固件库中对端口使用模式结构体定义如下: typedef enum { GPIO_Mode_AIN = 0x0, //模拟输入模式 GPIO_Mode_IN_FLOATING = 0x04, //浮空输入模式 GPI

C# 定义一个学生的结构体,输入学生信息,学号,姓名,身高,按身高排序输出

class Program { //定义一个结构体 struct student//student就是我们自己造的新数据类型 { public int code;//public修饰符 public string name;//结构体的成员 public decimal height; } static void Main(string[] args) { ArrayList arr = new ArrayList(); for (int i = 0; i < 3; i++) { student

类和结构体

//类  class A {     var a = 0 } let classA = A() classA.a = 12     //虽然classA定义为常量,但是仍然可以修改A类中的变量值;结构体则不可以 //类属于引用类型,结构体属于值类型

C语言结构体及函数传递数组参数示例

注:makeSphere()函数返回Sphere结构体,main函数中,调用makeSphere()函数,传递的第一个参数为数组,传递的数组作为指针. 版权声明:本文为博主原创文章,未经博主允许不得转载.