- //运行第一个程序
-
- package main
-
- func main(){
- print("Hello World")
- }
在GO语言中,一个程序只能有一个main包,对应只能有一个main方法,若无法满足这个条件,编译时将会报错。注释方式与PHP相同
个人在使用import时,按照自己的编写习惯,依赖IDE的自动导包功能,实现包的导入。若导入包后没有使用,会编译出错。
- // 使用 . 来实现省略调用
- import . "fmt"
-
- // 在包前通过别名替代包名
- import stdio "fmt"
-
- // 包前使用 _ 作用为只调取包的init方法
- import _ "xxx"
-
- // 使用 () 实现多包导入
- import (
- "fmt"
- "os"
- )
GO通过大小写来判别函数或者变量的权限,小写则为private,大写为public
GO定义数据类型比较有意思。在函数体内使用var定义的变量必须被使用,否则编译报错,申明外部变量没有限制
布尔类型只有true与false两个值,不可用0与1替代
int类型根据使用的平台自动判别32位还是64位,可以手动定义指定的位数,例如 int8/uint16,定义了指定8位的int型/16位的无符号int型
浮点型有float32/float64,精确范围对应7/15位
complex64/complex128
array struct string
slice map chan
inteface
func
- // 定义单个变量
- var hello = "Hello World"
-
- //定义多个变量
- var(
- num = 321
- str = "haha"
- )
-
- //定义常量,定义多个常量与变量的定义一样
- const PI =3.14
零值不等于空值,变量被声明为某种类型后的默认值,通常情况下整型的默认值为0,bool为false,string为空字符串
利用type进行类型别名的定义
- type(
- chinese string
- intMax int64
- )
- 变量的声明格式:var <name> <type>
- 变量的赋值格式:<name> = <value>
- 声明的同时赋值:var <name> [type] = <value>
- 自身推断赋值:var <name> = <value>
- 简写赋值(不可全局变量赋值使用) <name> := <value>
进行类型转换时,需要进行显式转换,并且需要保证两个不同的类型转换可以互相兼容
- var a = 'a'
- b := int(a)
常量值在编译时已经确定,所以右侧的数据需要使用常量或者内置函数,变量不能进行常量的赋值。定义常量组时,如果不进行数值的赋值,将会将其数值赋值为其上行的数值。常量初始化规则定义了每一行的常量定义个数一致时,默认上行数值下行初始化将进行,否则报错。
常量的iota是常量计数器,只在常量的表达式中使用。const中每新增一行常量声明将使iota计数一次
- // 赋值b,c均为hello字符串,赋值g,h为1,2
- const(
- a = "hello"
- b
- c
- e,f = 1,2
- g,h
- )
-
- // 输出 c为2 f为5
- const(
- a=1
- b
- c = iota
- d
- e
- f = iota
- )
运算符是一种特殊的符号,可以表示数据的运算,赋值,比较等
1)算术运算符

2)赋值运算符

3)比较运算符

4)逻辑运算符

5)位运算符

6)其他运算符

比较两个数的大小。
- package lee
-
- import "fmt"
-
- func Test(){
- a:=101
- b:=66
- if(a>b){
- fmt.Printf("a大一些")
- }else{
- fmt.Printf("b大一些")
- }
- }
注意:go语言不支持三元运算符

if条件判断:在布尔表达式里面可以定义变量,并行赋值.变量的作用域只能作用在代码块里面.
- // 格式:
- if <布尔表达式>{
- 语句块
- }else if <布尔表达式>{
- 语句块
- }else{
- 语句块
- }
-
- // 定义i=5 输出5,下面一句会编译出错
- if i:=5;i<10{
- print(i)
- }
- print(i)
go可以使用for完成所有的循环操作,变量的作用域只能作用在代码块里面
- //经典for循环结构
- for i:=1;i<100;i++{
- print(i)
- }
-
- //单条件(while式)for循环结构
- for true{
- print("进入死循环")
- }
-
- // 无条件式
- for {
- print("hello")
- }
switch不需要使用break,自动进行跳出,若需要连续条件选择,使用fallthrough。
- // 常规操作
- i := 3
- switch i{
- case 1:
- print(1)
- case 2:
- print(2)
- case 3:
- print(3)
- default:
- print(4)
- }
-
- // 在表达式中定义变量
- switch i=3; {
- case i==1:
- print(1)
- case i==2:
- print(2)
- case i==3:
- print(3)
- default:
- print(4)
- }
-
- // 使用fallthrough 输出2 3
- i := 2
- switch i{
- case 1:
- print(1)
- case 2:
- print(2)
- fallthrough
- case 3:
- print(3)
- default:
- print(4)
- }
goto break continue 三者均可以执行跳转。
goto用于调整执行位置。使用时,注意标签的位置
break用于循环语句中跳出循环,并开始执行循环之后的语句
continue不是跳出循环,而是跳过当前循环执行下一次循环语句,一般用于for 循环中,触发for增量语句的执行。
- //goto操作 这里输出 你好,这里是跳转
- START:
- print("你好,这里是跳转")
- os.Exit(1)
- for i:=1; i<3;i++ {
- goto START
- }
- print("这里是测试是否跳转")
-
- // break操作 输出 跳出了循环start
- START:
- for i:=1;i<=2 ;i++ {
- break START
- }
- print("跳出了循环start")
-
- //continue操作 输出 2 4 6 8
- for i:=1;i<10 ;i++ {
- if(i%2!=0){
- continue
- }
- print(i)
- }
数组的定义格式 var < name > [n]< type >。
数组赋值时,两个不同长度变量无法进行赋值操作。
go语言中 数组是一个值类型,使用时,直接对值进行操作,而不是地址引用。
两个长度相同的数组可以实现等于号判断。
- //常规定义
- var a [5]int
- //简写
- a:=[2]int{1,2}
- //索引赋值:将最后一个元素定义为5 其余为默认值
- a:=[20]int{19:5}
- //自动判断数组长度定义,使用三个点 编译器将会自动判断长度赋值
- a:=[...]int{11:5}
- //定义指针
- var p *[5]int
- //定义多维数组
- var arr = [2][3]int{}
- arr := [2][3]int{}
-
- //GO语言冒泡排序
- package main
- import "fmt"
- func main(){
- var a = [5]int{5,9,4,1,6}
- num := len(a)
- for i:=0;i
- for j:=i+1;j
- if(a[i]>a[j]){
- temp:=a[j]
- a[j] = a[i]
- a[i] = temp
- }
- }
- }
- fmt.Print(a)
- }
切片
一、切片的定义
在Go语言中,切片(Slice)是数组的一个引用。
它会生成一个指向数组的指针,并通过切片长度关联到底层数组部分或者全部元素。
切片还提供了一系列对数组的管理功能(append、copy),可以随时动态扩充存储空间,并且可以被随意传递而不会导致所管理的数组元素被重复复制。
根据以上特征,切片通常被用来实现变长数组,而且操作灵活。
切片的数据结构原型定义如下:
src/ pkg/ runtime/ runtime. h
- struct Slice
- { //must not move anything
- byte* array; //actual data
- unit32 len; //number of elements
- unit32 cap; //allocated number of elements
- };
由切片数据结构的原型定义可以看到,它抽象为以下三个部分:
指向被引用的底层数组的指针。
切片中元素的个数。
切片分配的存储空间。
二、切片的声明与创建
切片声明与创建的方法有三种:
1、基于底层数组创建
2、直接创建
3、使用make()函数创建。
1、基于底层数组创建
在创建切片时,可以基于一个底层数组,切片可以只使用数组的一部分元素或所有元素,甚至可以创建一个比底层数组还要大的数组切片,因为切片可以动态增长。创建切片的格式如下:
var sliceName [ ]dataType
说明:
切片名的命名规则和变量名相同,遵循标识符命名规则。
在创建切片时,不要指定切片的长度。
切片的类型可以是Go语言的任何基本数据类型。
例如:
var slice1 [] int
上例中定义了一个整型切片slicel,注意不要指定切片长度,如果指定了长度就成了定义数组了。
当一个切片定义好以后,如果还没有被初始化,默认值为nil, 而且切片的长度为0。切片的长度可以使用内置函数len()获取,还可以使用内置函数cap()获取切片的内存容量。
所以,当一个切片定义好以后,还要对切片进行初始化,这样切片才可用。对于上例,假如已经定义了一个整型数组array1,则切片slice1的初始化方式如下:
slice1 = array1[start : end]
从上式可以看到,Go语言支持以array1[start : end]的方式基于一个底层数组来生成切片,即切片引用的数组元素由array1[start]到 array1[end],但不包含array1[end]。
如果要引用底层数组的所有元素,可采取的方式如下:
- slicel = array1
- slice1 = array1[ :]
- slicel = array1[0: len(array1)]
2、直接创建切片
直接创建切片,即在定义切片的时候初始化切片元素,例如:
var slice1 =[]int{1,2,3,4,5}
3、使用make函数创建切片
内置函数make()用于灵活的创建切片
var slicel = make([]int,5)
上式创建了一个有5个元素的整型切片slicel,元素的初值为0。
在使用make()函数创建切片时,还可以为切片元素预留存储空间。例如:
var slice1 = make([]int, 5,10)
上式表示,创建整型切片slice1,元素个数为5,元素初值为0,并预留10个元素的存储空间。
三、切片元素的访问与遍历
切片元素的遍历和数组元素的遍历一样,要通过元素下标访问,另外也可以使用关键字range遍历所有切片元素。
切片元素访问的一般格式如下:
sliceName [sliceIndex]
遍历同数组,使用range关键字表达式,有两个返回值,第一个是元素的下标,第二个是元素的值。
四、切片的操作
1、切片元素的增加
可以使用append()函数向切片尾部添加新元素,这些元素保存到底层数组。append并不会影响原来切片的属性,它返回变更后新的切片对象。
与数组相比,除了都有长度(length)以外,切片多了一个容量(capacity)的概念,即切片中元素的个数和分配的存储空间是两个不同的值。如果在增加新元素时超出cap的限制,则底层会重新分配一块“够大”的内存,一般来说是将原来的内存空间扩大二倍,然后再将数据从原来的内存复制到新的内存块。
2、切片元素的复制
使用切片长时间引用“超大”的底层数组,会导致严重的内存浪费。
可以新建一个小的slice对象,然后将所需的数据复制过去。
函数copy()可以在切片之间复制元素,能够复制的数量取决于复制方和被复制方的长度值,通常取最小值。
需要注意的是,在同一底层数组的不同切片间复制元素时,元素位置会发生重叠。
- //切片的复制
- package main
-
- import(
- "fmt"
- )
-
- func main() {
- var slicel= []int{1,2,3,4,5,6,7,8,9,10}
- var slice2 = make([ ] int,3, 5)
- var n int
- //只能复制三个元素
- n= copy(slice2,slice1)
- fmt. Println(n, slice2, len( slice2), cap(slice2))
- //slice3和slice1指向同一底层数组
- slice3 : = slice1[3:6]
- //复制后元素重叠
- n= copy(slice3, slice1[1:5])
- fmt.Println(n, slicel, slice3)
- }
-
- 编译并运行程序输出结果为:
- 3 [1 2 3] 3 5
- 3 [1 2 3 2 3 4 7 8 9 10] [2 3 4]
通过输出结果可以看出,在将slice1复制到slice2时,由于slice2的长度最小为3,所以只能将slice1的前三个元素复制给slice2。而将slicel1复制到slice3 时,由于slicel1和slice3指向同一个底层数组,所以复制后元素重叠。slice3刚创建时,它引用的是底层数组的[4,5,6]三个元素,复制后slice1将[2,3,4]三个元素复制给slice3 ,所以最后slice3 的元素[2,3,4]覆盖了slice1的元素[4,5,6]。
3、排序和搜索切片
标准库中的sort包提供了对整型、浮点型和字符串类型切片进行排序的函数,检查一个切片是否排序好的函数,以及使用二分搜索算法在一个有序切片中搜索-一个元素的函数。 同时提供了通用sort.Sort ()和sort.Search ()函数,可用于任何自定义的数据。
函数
1.简介
- 函数:为完成某一功能的程序指令(语句)的集合
- 在Go中,函数分为自定义函数、系统函数
2.基本语法
- func 函数名(形参列表) (返回值列表) {
- 函数体
- return 返回值列表
- }
3.递归
- 函数体内调用自己
- package main
-
- import "fmt"
-
- func test(n int) {
- if n > 2 {
- n--
- test(n)
- }
- fmt.Println("n = ", n)
- }
-
- func main() {
- test(4)
- }
- 执行一个函数时,就创建一个新的受保护的独立空间
- 函数的局部变量是独立的,不会相互影响
- 递归必须向退出递归的条件逼近,否则就会出现无限递归
- 当一个函数执行完毕,或者遇到
return,就会返回,遵守谁调用就将结果返回给谁。
4.递归练习
- 1.求第N个斐波那契数列对应的值
- package main
-
- import "fmt"
-
- func feb(n int) int {
- if n <= 2 {
- return 1
- }
- return test(n-1) + test(n-2)
- }
-
- func main() {
- result := feb(6)
- fmt.Println(result)
- }
- 2.已知函数
f(1) = 3,f(n) = 2*f(n-1) + 1,求f(n)的值
- package main
-
- import "fmt"
-
- func test(n int) int {
- if n == 1 {
- return 3
- }
- return 2*test(n-1) + 1
- }
-
- func main() {
- result := test(6)
- fmt.Println(result)
- }
-
- 3.有一堆桃子,猴子第一天吃了其中的一半,并在多吃了一个!以后每天猴子都吃其中的一半,然后再多吃一个。当到
第十天准备吃时,发现只剩了1个桃子。问题:最初总共多少个桃子

- 从上图可以看出其通项公式为:
(1 + f(n+1))* 2,n代表天数
- package main
-
- import "fmt"
-
- func getPeach(n int) int {
- if n == 10 {
- return 1
- }
- return (1 + getPeach(n+1)) * 2
- }
-
- func main() {
- result := getPeach(1)
- fmt.Println(result)
- }
5.函数使用注意细节
-
1.函数的形参列表和返回值列表都可以是多个
-
2.形参列表和返回值列表都可以是值类型或引用类型
-
3.函数命名遵循标识符命名规则,首字母不能是数字,首字母如果是大写,则可以被其他文件或包调用,否则只能在当前文件被调用
-
4.函数的变量是局部的,函数外不生效
-
5.基本类型和数组默认都是值传递,即进行值拷贝,在函数内修改,不会影响到原来的值
-
6.如果希望函数内的变量能修改函数外的变量,可以传递变量的地址&,函数内以指针方式操做变量
-
7.Go函数不支持重载(即一个包下不允许存在同名的函数)
-
8.在Go语言中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量,通过该变量可以对函数进行调用
-
9.函数既然是一种数据类型,因此在Go语言中,函数可以作为形参,并且调用
- package main
-
- import "fmt"
-
- func test(myFunc func(int, int) int, num1, num2 int) int {
- return myFunc(num1, num2)
- }
-
- func getSum(a, b int) int {
- return a + b
- }
- func main() {
- resp := test(getSum, 1, 2)
- fmt.Println(resp)
- }
-
10.为了简化数据类型定义,Go语言支持自定义数据类型
- 基本语法:
type myInt int,myInt就可以当作int类型来使用,但不完全一致,不能将一个myInt类型的值直接赋值给int类型的变量,需要使用int()来强转一下。 - 也可以使用type来定义一个函数类型
- package main
-
- import "fmt"
-
- type myFuncType func(int, int) int
-
- func test(myFunc myFuncType, num1, num2 int) int {
- return myFunc(num1, num2)
- }
-
- func getSum(a, b int) int {
- return a + b
- }
-
- func main() {
- resp := test(getSum, 1, 2)
- fmt.Println(resp)
- }
-
11.支持对函数返回值命名
- package main
-
- import "fmt"
-
- type myFuncType func(int, int) int
-
- func test(myFunc myFuncType, num1, num2 int) int {
- return myFunc(num1, num2)
- }
-
- // 将函数返回值重命名为sum
- func getSum(a, b int) (sum int) {
- sum = a + b
- return
- }
-
- func main() {
- resp := test(getSum, 1, 2)
- fmt.Println(resp)
- }
-
12.使用_来忽略返回值
-
13.Go支持可变参数参数名...,必须放在参数最后位置
- package main
-
- import "fmt"
-
- func getSum(args ...int) int {
- sum := 0
- for i := 0; i < len(args); i++ {
- sum += args[i]
- }
- return sum
- }
- func main() {
- resp := getSum(1, 2, 3)
- fmt.Println(resp)
- }
6.init函数
- 每个源文件都可以包含一个init函数,该函数会在
main函数前执行,被Go运行框架调用。 - 通常在init函数中完成初始化工作,每个文件都可以有一个init函数
- package main
-
- import "fmt"
-
- func init() {
- fmt.Println("init函数自动执行")
- }
-
- func main() {
- fmt.Println("开始执行主函数")
- }
- 如果一个文件中同时包含
全局变量、init函数、main函数,则执行顺序为:全局变量 > init > main - package main
-
- import "fmt"
-
- var money = test()
-
- func test() int {
- fmt.Println("test()")
- return 100
- }
-
- func init() {
- fmt.Println("init函数自动执行")
- }
-
- func main() {
- fmt.Println("开始执行主函数...money=", money)
- }
-
- // test()
- // init函数自动执行
- // 开始执行主函数...money= 100
7.匿名函数
Go支持匿名函数,如果我们某个函数只希望使用一次,可以考虑使用匿名函数,匿名函数可以实现多次调用
- 示例一:在定义时就调用
- package main
-
- import "fmt"
-
- func main() {
- res := func(n1, n2 int) int {
- return n1 + n2
- }(10, 20)
- fmt.Println("result =", res)
- }
- 示例二:将匿名函数赋值给一个变量(函数变量),再通过该变量来调用匿名函数
- package main
-
- import "fmt"
-
- func main() {
- sum := func(n1, n2 int) int {
- return n1 + n2
- }
-
- res := sum(10, 20)
- fmt.Println("result =", res)
- }
- 示例三:全匿名函数,将函数赋值给一个全局变量,就成为一个全局函数,可以在程序有效
- package main
-
- import "fmt"
-
- var multi = func(n1, n2 int) int {
- return n1 * n2
- }
-
- func main() {
- res := multi(10, 20)
- fmt.Println("result =", res)
- }
8.闭包
-
闭包就是一个函数和与其相关的引用环境组合的一个整体
-
闭包必须满足三个条件:
1、必须有一个内嵌函数
2、内嵌函数必须引用外部函数中的变量
3、外部函数返回值必须是内嵌函数
-
闭包可以使得变量常驻内存
- package main
-
- import "fmt"
-
- func Closure() func(int) int {
- var n1 = 10
- return func(n2 int) int {
- n1 = n1 + n2
- return n1
-
- // return n1 + n2 // 这样的结果完全不一样, n1 = n1 + n2会修改局部变量n1的值,如果直接返回n1 + n2,则不会修改局部变量n1的值
- }
- }
-
- func main() {
- res := Closure()
- fmt.Println("result =", res(30)) // 40
- fmt.Println("result =", res(31)) // 71
- }
-
nodejs
- function closure() {
- var a = 10;
- function inner(b) {
- a = a + b;
- return a
- }
- return inner;
- }
- var func = closure();
- console.log(func(30)); // 40
- console.log(func(31)); // 71
-
python
- # 变量 a 对于 inner来说是外部变量,因此不能直接进行修改
- def closure():
- a = 10
- def inner(b):
- a = a + b
- return a
- return inner
-
- # UnboundLocalError: local variable 'a' referenced before assignment
-
- # 但对于inner来说是可以直接使用的
- def closure():
- a = 10
- def inner(b):
- return a + b
- return inner
-
- # 必须使用 nonlocal 来修改变量a的作用域,从而对其进行操做
- def closure():
- a = 10
- def inner(b):
- nonlocal a
- a = a + b
- return a
- return inner
-
- func = closure()
- print(func(30)) # 40
- print(func(31)) # 71
-
案例:使用闭包方式,实现检查文件后缀名是否为.jpg,如果不是,则内部实现拼接.jpg,否则直接返回
- package main
-
- import (
- "fmt"
- "strings"
- )
-
- func Closure(endFix string) func(string) string {
- return func(name string) string {
- if strings.HasSuffix(name, endFix) {
- return name
- }
- return name + endFix
- }
- }
-
- func main() {
- res := Closure(".jpg")
- fmt.Println("result =", res("aaa.jpg"))
- fmt.Println("result =", res("bbb"))
- }
9.函数参数传递
- 值类型:基本数据类型:int系列、float系列、bool、string、数组、结构体
- 引用类型:指针、slice切片、map、管道chan、interface等
结构体
结构体是一种用户自定义的数据类型,它由一组字段组成,每个字段可以是任意基本类型或其他结构体类型。结构体在Go语言中被广泛使用,它可以用来表示复杂的数据结构,比如二叉树、链表、图等。
一个简单的结构体定义如下:
- copy codetype Person struct {
- name string
- age int
- gender string
- }
上面的代码定义了一个名为Person的结构体,它有三个字段,分别是name、age和gender,它们的类型分别为string、int和string。我们可以通过该结构体来表示一个人的基本信息。
1.结构体的语法
Go语言中结构体的语法非常简洁,它的基本形式如下:
- copy codetype 结构体名 struct {
- 字段1 类型1
- 字段2 类型2
- ...
- 字段n 类型n
- }
其中,结构体名是用户自定义的标识符,用于表示该结构体的类型。字段是结构体中的成员,每个字段都有一个对应的类型。在定义结构体时,可以使用任何基本类型或其他结构体类型作为字段的类型。另外,结构体中的字段可以使用大写字母开头的标识符表示公有成员,小写字母开头的标识符表示私有成员。
2.结构体的初始化
在Go语言中,结构体类型的变量可以通过结构体字面量来进行初始化。结构体字面量是一种简洁的语法,可以用于快速创建一个结构体类型的变量。
结构体字面量的基本形式如下:
- copy codevar 变量名 = 结构体类型{
- 字段1: 值1,
- 字段2: 值2,
- ...
- 字段n: 值n,
- }
其中,变量名是结构体类型的变量名,结构体类型是用户自定义的结构体类型,字段是结构体中的成员,值是该成员对应的初始化值。我们可以省略字段名,只提供值,此时Go语言会按照结构体定义时的字段顺序来进行初始化。例如:
- copy codevar p1 = Person{
- "张三",
- 18,
- "男",
- }
-
- var p2 = Person{
- name: "李四",
- age: 20,
- gender: "女",
- }
上面的代码分别创建了两个Person类型的变量p1和p2,它们的字段值分别为{张三 18 男}和{李四 20 女}。可以看出,结构体字面量提供了一种简单、直观的方式来初始化结构体类型的变量。
3.结构体的访问
在Go语言中,可以通过结构体变量的字段名来访问结构体中的成员。例如:
- copy codevar p Person
- p.name = "张三"
- p.age = 18
- p.gender = "男"
上面的代码创建了一个名为p的Person类型的变量,并对其成员进行了赋值。可以看出,访问结构体成员的语法非常简单,只需要使用点号(.)连接结构体变量和成员名即可。
4.结构体的方法
Go语言中的结构体还支持方法,方法是一种特殊的函数,它可以与结构体类型关联。方法与函数的区别在于,方法必须在结构体类型上定义,而函数可以在任何地方定义。另外,方法可以访问结构体的成员,而函数只能访问其参数。
Go语言中的方法定义如下:
- copy codefunc (接收者变量 接收者类型) 方法名(参数列表) 返回值列表 {
- // 方法体
- }
其中,接收者变量是一个标识符,用于表示方法所属的结构体类型的变量。接收者类型是方法所属的结构体类型,参数列表和返回值列表与普通函数的定义方式相同。
下面是一个例子:
- copy codetype Rectangle struct {
- width, height float64
- }
-
- func (r Rectangle) Area() float64 {
- return r.width * r.height
- }
-
- func main() {
- r := Rectangle{3, 4}
- fmt.Println("面积:", r.Area())
- }
上面的代码定义了一个名为Rectangle的结构体,它有两个字段width和height。该结构体还定义了一个名为Area的方法,用于计算矩形的面积。
在main函数中,创建了一个Rectangle类型的变量r,并调用其Area方法来计算面积。
5.结构体的嵌套
在Go语言中,结构体可以嵌套在其他结构体中,从而形成更复杂的数据结构。嵌套结构体的定义方式与普通结构体的定义方式相同,只是在字段的类型中指定另一个结构体类型。
下面是一个例子:
- copy codetype Address struct {
- Province string
- City string
- }
-
- type Person struct {
- Name string
- Age int
- Address Address
- }
-
- func main() {
- p := Person{
- Name: "张三",
- Age: 18,
- Address: Address{
- Province: "广东省",
- City: "深圳市",
- },
- }
-
- fmt.Println(p)
- }
上面的代码定义了两个结构体类型,Address和Person。Person结构体中包含一个Address类型的字段,用于表示该人员的地址信息。
在main函数中,创建了一个Person类型的变量p,并对其成员进行了赋值。可以看出,嵌套结构体提供了一种简单、灵活的方式来表示复杂的数据结构。
6.结构体的匿名字段
在Go语言中,结构体还支持匿名字段。匿名字段是一种特殊的字段类型,它没有字段名,只有字段类型。在结构体中,可以使用匿名字段来表示继承关系或者组合关系。
下面是一个例子:
- copy codetype Person struct {
- string
- int
- }
-
- func main() {
- p := Person{"张三", 18}
- fmt.Println(p.string, p.int)
- }
上面的代码定义了一个Person结构体,它包含了一个string类型的匿名字段和一个int类型的匿名字段。在main函数中,创建了一个Person类型的变量p,并对其成员进行了访问。可以看出,使用匿名字段可以在一定程度上简化代码。
7.结构体的标签
在Go语言中,结构体的字段可以使用标签(tag)来进行注释或者元数据的传递。标签是一个字符串,它的格式为key:"value",其中key表示标签的名称,value表示标签的值。
下面是一个例子:
- copy codetype Person struct {
- Name string `json:"name"`
- Age int `json:"age"`
- }
-
- func main() {
- p := Person{"张三", 18}
- b, _ := json.Marshal(p)
- fmt.Println(string(b))
- }
上面的代码定义了一个Person结构体,它有两个字段Name和Age。在Name字段和Age字段上,我们使用了json标签,用于指定json序列化时使用的字段名。
在main函数中,创建了一个Person类型的变量p,并将其序列化为json字符串。可以看出,使用标签可以方便地进行元数据传递和注释。
8.结构体的应用场景
在Go语言中,结构体被广泛应用于各种数据结构的定义和实现。下面是一些常见的应用场景:
- 数据库ORM:结构体可以与数据库表进行映射,从而实现对象关系映射(ORM)功能。
- 网络编程:结构体可以用于表示网络数据包的格式,从而实现网络编程功能。
- 并发编程:结构体可以用于实现并发编程模型,例如管道、锁和条件变量等。
- 配置文件:结构体可以用于表示配置文件的格式,从而实现配置文件读写功能。
- 模板引擎:结构体可以用于表示模板数据,从而实现模板引擎功能。
-
相关阅读:
win10 上安装 pytorch + cuda
3、后台数据库连接以及工具类编写 [木字楠博客]
walking机器人仿真教程-深度学习-使用yolov5进行物体识别
alpha-beta剪枝
27.4 Java集合之Map学习
今天虚竹哥又发现了一款好用的国产化API工具
汇川IT7000系列HMI使用脚本实现画面跳转时自动切换手自动模式
Oracle SQL执行计划操作(7)——排序相关操作
QT+OSG/osgEarth编译之三十二:Exiv2+Qt编译(一套代码、一套框架,跨平台编译,版本:Exiv2-0.27.5)
第三节:kafka sarama 遇到Bug?
-
原文地址:https://blog.csdn.net/Lyon_yong/article/details/136606844