首页 > 其他分享 >Go中结构体基础知识总结

Go中结构体基础知识总结

时间:2022-10-25 23:01:52浏览次数:60  
标签:总结 string firstName int fmt 基础知识 Println Go main

什么是结构体

结构是表示字段集合的用户定义类型。它可以用于将数据分组为单个单元而不是将每个数据作为单独的值的地方。 例如,员工有firstName、lastName和age。将这三个属性分组到一个名为Employee

type Employee struct {
firstName string
lastName  string
age       int
}

上面的代码段声明了一个结构类型Employee,其中包含字段firstName、lastName和age。上面的Employee结构称为命名结构,因为它创建了一个名为Employme的新数据类型,可以使用该数据类型创建Employ结构。 通过在一行中声明属于同一类型的字段,然后在类型名称后面加上该字段,也可以使该结构更加紧凑。在上面的struct中,firstName和lastName属于同一类型字符串,因此该struct可以重写为:

type Employee struct {
firstName, lastName string
age                 int
}

尽管上面的语法节省了几行代码,但它并没有使字段声明显式。请避免使用上述语法。

创建结构体

让我们使用以下简单程序声明一个命名的structEmployee。

package main

import (
	"fmt"
)

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

func main() {

	//creating struct specifying field names
	emp1 := Employee{
		firstName: "Sam",
		age:       25,
		salary:    500,
		lastName:  "Anderson",
	}

	//creating struct without specifying field names
	emp2 := Employee{"Thomas", "Paul", 29, 800}

	fmt.Println("Employee 1", emp1)
	fmt.Println("Employee 2", emp2)
}

在上述程序的第7行中,我们创建了一个命名的结构类型Employee。在上述程序的第17行中,emp1结构是通过为每个字段名指定值来定义的。声明结构类型时,字段的顺序不必与字段名的顺序相同。在这种情况下。我们已更改lastName的位置并将其移到末尾。这将不会有任何问题。 在上述程序的第25行中,通过省略字段名来定义emp2。在这种情况下,必须保持字段的顺序与结构声明中指定的顺序相同。请避免使用此语法,因为它会使您难以确定哪个字段的值。我们在此处指定此格式只是为了理解这也是一个有效语法:) 以上程序打印为:

Employee 1 {Sam Anderson 25 500}
Employee 2 {Thomas Paul 29 800}  

创建匿名结构体

可以在不创建新数据类型的情况下声明结构。这些类型的结构称为匿名结构。

package main

import (
	"fmt"
)

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

	fmt.Println("Employee 3", emp3)
}

在上述程序的第8行中,定义了一个匿名结构变量emp3。正如我们已经提到的,这个结构称为anonymous,因为它只创建一个新的结构变量emp3,而没有定义任何新的结构类型,如命名结构。

上述代码打印的结果为:

Employee 3 {Andreah Nikola 31 5000}  

访问结构体字段

运算符.用于访问结构的各个字段。

package main

import (
	"fmt"
)

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

func main() {
	emp6 := Employee{
		firstName: "Sam",
		lastName:  "Anderson",
		age:       55,
		salary:    6000,
	}
	fmt.Println("First Name:", emp6.firstName)
	fmt.Println("Last Name:", emp6.lastName)
	fmt.Println("Age:", emp6.age)
	fmt.Printf("Salary: $%d\n", emp6.salary)
	emp6.salary = 6500
	fmt.Printf("New Salary: $%d", emp6.salary)
}

上面程序中的emp6.firstName访问emp6结构的firstName字段。在第25行中,我们修改了员工的工资。此程序打印。

First Name: Sam
Last Name: Anderson
Age: 55
Salary: $6000
New Salary: $6500 

结构体零值

当定义了一个结构并且没有用任何值显式初始化它时,默认情况下会为该结构的字段分配零值。

package main

import (
	"fmt"
)

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

func main() {
	var emp4 Employee //zero valued struct
	fmt.Println("First Name:", emp4.firstName)
	fmt.Println("Last Name:", emp4.lastName)
	fmt.Println("Age:", emp4.age)
	fmt.Println("Salary:", emp4.salary)
}

上面的程序定义了emp4,但没有用任何值初始化。因此,firstName和lastName被指定为字符串的零值,字符串为空字符串“”,age和salary被指定为零值int,即0。此程序打印

First Name:
Last Name:
Age: 0
Salary: 0  

也可以为某些字段指定值,而忽略其余字段。在这种情况下,被忽略的字段被赋值为零。

package main

import (
	"fmt"
)

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

func main() {
	emp5 := Employee{
		firstName: "John",
		lastName:  "Paul",
	}
	fmt.Println("First Name:", emp5.firstName)
	fmt.Println("Last Name:", emp5.lastName)
	fmt.Println("Age:", emp5.age)
	fmt.Println("Salary:", emp5.salary)
}

在上面的程序中。第16号和第17号,firstName和lastName被初始化,而年龄和薪水没有初始化。因此,年龄和工资被指定为零值。此程序输出:

First Name: John
Last Name: Paul
Age: 0
Salary: 0  

结构体指针

也可以创建指向结构的指针。

package main

import (
	"fmt"
)

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

func main() {
	emp8 := &Employee{
		firstName: "Sam",
		lastName:  "Anderson",
		age:       55,
		salary:    6000,
	}
	fmt.Println("First Name:", (*emp8).firstName)
	fmt.Println("Age:", (*emp8).age)
}

上面程序中的emp8是指向Employee结构的指针。(*emp8)。firstName是访问emp8结构的firstName字段的语法。此程序打印:

First Name: Sam
Age: 55 

Go语言为我们提供了使用emp8.firstName而不是显式取消引用(*emp8)的选项。firstName以访问firstName字段。

package main

import (
	"fmt"
)

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

func main() {
	emp8 := &Employee{
		firstName: "Sam",
		lastName:  "Anderson",
		age:       55,
		salary:    6000,
	}
	fmt.Println("First Name:", emp8.firstName)
	fmt.Println("Age:", emp8.age)
}

我们已经使用emp8.firstName访问上述程序中的firstName字段,该程序还输出:

First Name: Sam
Age: 55 

匿名字段

可以使用只包含类型而不包含字段名的字段创建结构。这类字段称为匿名字段。下面的代码段创建了一个struct Person,它有两个匿名字段string和int:

type Person struct {
string
int
}

即使匿名字段没有显式名称,默认情况下,匿名字段的名称是其类型的名称。例如,在上面的Person结构中,虽然字段是匿名的,但默认情况下它们采用字段类型的名称。所以Person结构有两个字段,分别是名称字符串和int。

package main

import (
	"fmt"
)

type Person struct {
	string
	int
}

func main() {
	p1 := Person{
		string: "naveen",
		int:    50,
	}
	fmt.Println(p1.string)
	fmt.Println(p1.int)
}

在上述程序的第17行和第18行中,我们访问Person结构的匿名字段,使用它们的类型作为字段名,分别是string和int。上述程序的输出为:

naveen
50 

结构体嵌套

结构可能包含字段,而字段又是结构。这些类型的结构称为嵌套结构。

package main

import (
	"fmt"
)

type Address struct {
	city  string
	state string
}

type Person struct {
	name    string
	age     int
	address Address
}

func main() {
	p := Person{
		name: "Naveen",
		age:  50,
		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结构具有字段地址,而字段地址又是一个结构。此程序打印:

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

字段升级

属于结构中匿名结构字段的字段称为提升字段,因为可以像访问包含匿名结构字段结构一样访问它们。我可以理解这个定义相当复杂,所以让我们深入研究一些代码来理解它。

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

在上面的代码段中,Person结构有一个匿名字段Address,它是一个结构。现在,Address的字段,即city和state,被称为promoted字段,因为可以像直接在Person结构本身中声明一样访问它们。

package main

import (
	"fmt"
)

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

func main() {
	p := Person{
		name: "Naveen",
		age:  50,
		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
}

在上面程序的第29行和第30行中,可以访问提升字段city和state,就好像它们是使用语法p.city和p.state在结构p中声明的一样。此程序打印:

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

结构体导出

如果结构类型以大写字母开头,则它是导出类型,可以从其他包访问。类似地,如果结构的字段以caps开头,则可以从其他包访问它们。让我们编写一个具有自定义包的程序来更好地理解这一点。在Documents目录中创建名为structs的文件夹。请随意在任何您喜欢的地方创建它。我更喜欢我的文档目录。

mkdir ~/Documents/structs  

创建一个gomod,并命名为structs

cd ~/Documents/structs/
go mod init structs

创建另外一个目录computer申明一个结构体。

mkdir computer  

创建一个spec.go文件,并写入如下内容:

package computer

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

}

上面的代码片段创建了一个程序包计算机,其中包含一个导出的结构类型Spec,其中有两个导出的字段Maker和Price,以及一个未导出的字段模型。让我们从主包导入这个包并使用Spec结构。 创建名为main的文件。进入structs目录并在main.go中编写以下程序:

package main

import (
	"structs/computer"
	"fmt"
)

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

这个结构体如下结构体:

├── structs
│   ├── computer
│   │   └── spec.go
│   ├── go.mod
│   └── main.go

在上面程序的第4行,我们导入计算机包。在第13行和第14行,我们访问struct Spec的两个导出字段Maker和Price。这个程序可以通过执行命令go-install,然后执行structs命令来运行。

go install
structs  

运行之后如下结果:

Maker: apple
Price: 50000 

如果我们试图访问未报告的字段模型,编译器会抱怨。更换main的内容。使用以下代码。

package main

import (  
    "structs/computer"
    "fmt"
)

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

在上述程序的第12行中,我们尝试访问未报告的字段模型。运行此程序将导致编译错误。

# structs
./main.go:12:13: unknown field 'model' in struct literal of type computer.Spec

由于模型字段未报告,因此无法从其他包访问它。

结构体比较

结构是值类型,如果它们的每个字段都是可比较的,则可以进行比较。如果两个结构变量的对应字段相等,则认为它们相等。

package main

import (
	"fmt"
)

type name struct {
	firstName string
	lastName  string
}

func main() {
	name1 := name{
		firstName: "Steve",
		lastName:  "Jobs",
	}
	name2 := name{
		firstName: "Steve",
		lastName:  "Jobs",
	}
	if name1 == name2 {
		fmt.Println("name1 and name2 are equal")
	} else {
		fmt.Println("name1 and name2 are not equal")
	}

	name3 := name{
		firstName: "Steve",
		lastName:  "Jobs",
	}
	name4 := name{
		firstName: "Steve",
	}

	if name3 == name4 {
		fmt.Println("name3 and name4 are equal")
	} else {
		fmt.Println("name3 and name4 are not equal")
	}
}

在上面的程序中,名称结构类型包含两个字符串字段。由于字符串是可比较的,因此可以比较类型名的两个结构变量。在上面的程序中,name1和name2相等,而name3和name4不相等。此程序将输出:

name1 and name2 are equal
name3 and name4 are not equal 

如果结构变量包含不可比较的字段,那么它们就不可比较(感谢reddit的alasija指出这一点)。

package main

import (
	"fmt"
)

type image struct {
	data map[int]int
}

func main() {
	image1 := image{
		data: map[int]int{
			0: 155,
		}}
	image2 := image{
		data: map[int]int{
			0: 155,
		}}
	if image1 == image2 {
		fmt.Println("image1 and image2 are equal")
	}
}

在上面的程序中,图像结构类型包含类型映射的字段数据。地图是不可比较的,因此无法比较image1和image2。如果运行此程序,编译将失败并返回错误。

./prog.go:20:12: invalid operation: image1 == image2 (struct containing map[int]int cannot be compared)

标签:总结,string,firstName,int,fmt,基础知识,Println,Go,main
From: https://blog.51cto.com/u_10992108/5795153

相关文章

  • 上篇:Go的反射基础
    什么是反射反射的机制是在运行时可以获取到其变量的类型和值,且可以在运行时对其变量类型和值进行检查,可以对其值进行修改。这种机制,其实在编写业务代码时是比较少用到的,......
  • 全球名校AI课程库(27)| MIT麻省理工 · 数据结构与算法设计课程『Design and Analysis o
    ......
  • golang获取0点时间戳
    1.获取当地时间0点时间戳funcGetZeroTime()int64{   nowTime:=time.Now()   now:=nowTime.Unix()   _,offsetSeconds:=nowTime.Zone()      ......
  • Linux基础知识一
    Linux基础知识一Linux目录结构/bin:Binaries,存放的都是二进制文件,包括一些常用的命令,例如:ls、cat/boot:存放系统内核和启动需要的文件,Linux的核心文件。/dev:存放......
  • GO语言从入门到精通全套教程
    资源简介本套教程分为两部分:包括Go编程基础和GoWeb基础。从GO语言基础知识的讲解到后面的实战开发,让您快速掌握GO语言编程技术。教程画质高清。下载地址:https://pan.ba......
  • 深度学习基础知识
    深度学习基础知识本博客用以整理他人发布的基础知识fine-tuningWhatisFine-tuninginNeuralNetworks?......
  • 第十二章学习总结
    第12章块设备I/O和缓冲区管理一、知识点总结12.1块设备I/O和缓冲区I/O缓冲的基本原理非常简单。文件系统使用一系列I/O缓冲区作为块设备的缓存内存。当进程试图读......
  • 快速启动mongodb和mongo-express
    文档说明:只记录关键地方;试验环境:linuxdebian11mongodb和mongo-webUIversion:"3"services:mongodb-server:image:mongo:latestcontainer_......
  • 【Django Admin】 自定义按钮 不勾选也可以执行
    #自定义按钮不勾选也可以执行defchangelist_view(self,request,extra_context=None):if'action'inrequest.POSTandrequest.POST['action']=......
  • Chandler Carruth talk 总结
    简介ChandlerCarruth算是我在CppCon上面最喜欢的一个老哥,他现在是在google的llvm组做编译器相关的工作,他的talk幽默风趣,并且喜欢说一些性能优化相关的东西,作为一个cpper,......