Go的数据类型定义
Go
//运行第一个程序
package main
func main(){
print("Hello World")
}
在GO语言中,一个程序只能有一个main包,对应只能有一个main方法,若无法满足这个条件,编译时将会报错。注释方式与PHP相同
- import的使用
个人在使用import时,按照自己的编写习惯,依赖IDE的自动导包功能,实现包的导入。若导入包后没有使用,会编译出错。
Go
// 使用 . 来实现省略调用
import . "fmt"
// 在包前通过别名替代包名
import stdio "fmt"
// 包前使用 _ 作用为只调取包的init方法
import _ "xxx"
// 使用 () 实现多包导入
import (
"fmt"
"os"
)
- GO的可见性
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
Go
// 定义单个变量
var hello = "Hello World"
//定义多个变量
var(
num = 321
str = "haha"
)
//定义常量,定义多个常量与变量的定义一样
const PI =3.14
- 类型零值
零值不等于空值,变量被声明为某种类型后的默认值,通常情况下整型的默认值为0,bool为false,string为空字符串
- 类型别名的定义
利用type进行类型别名的定义
Go
type(
chinese string
intMax int64
)
-
变量声明与赋值
变量的声明格式:var <name> <type>
变量的赋值格式:<name> = <value>
声明的同时赋值:var <name> [type] = <value>
自身推断赋值:var <name> = <value>
简写赋值(不可全局变量赋值使用) <name> := <value> -
类型转换
进行类型转换时,需要进行显式转换,并且需要保证两个不同的类型转换可以互相兼容
Go
var a = 'a'
b := int(a)
- 常量的定义问题
常量值在编译时已经确定,所以右侧的数据需要使用常量或者内置函数,变量不能进行常量的赋值。定义常量组时,如果不进行数值的赋值,将会将其数值赋值为其上行的数值。常量初始化规则定义了每一行的常量定义个数一致时,默认上行数值下行初始化将进行,否则报错。
常量的iota是常量计数器,只在常量的表达式中使用。const中每新增一行常量声明将使iota计数一次
Go
// 赋值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、运算符的基本介绍
运算符是一种特殊的符号,可以表示数据的运算,赋值,比较等
1)算术运算符
2)赋值运算符
3)比较运算符
4)逻辑运算符
5)位运算符
6)其他运算符
比较两个数的大小。
Go
package lee
import "fmt"
func Test(){
a:=101
b:=66
if(a>b){
fmt.Printf("a大一些")
}else{
fmt.Printf("b大一些")
}
}
注意:go语言不支持三元运算符
2、运算符的优先级
控制语句
- if条件判断
if条件判断:在布尔表达式里面可以定义变量,并行赋值.变量的作用域只能作用在代码块里面.
Go
// 格式:
if <布尔表达式>{
语句块
}else if <布尔表达式>{
语句块
}else{
语句块
}
// 定义i=5 输出5,下面一句会编译出错
if i:=5;i<10{
print(i)
}
print(i)
- 循环控制
go可以使用for完成所有的循环操作,变量的作用域只能作用在代码块里面
Go
//经典for循环结构
for i:=1;i<100;i++{
print(i)
}
//单条件(while式)for循环结构
for true{
print("进入死循环")
}
// 无条件式
for {
print("hello")
}
- switch语句
switch不需要使用break,自动进行跳出,若需要连续条件选择,使用fallthrough。
Go
// 常规操作
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增量语句的执行。
Go
//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语言中 数组是一个值类型,使用时,直接对值进行操作,而不是地址引用。
两个长度相同的数组可以实现等于号判断。
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<num ;i++ {
for j:=i+1;j<num ;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
Go
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、基于底层数组创建
在创建切片时,可以基于一个底层数组,切片可以只使用数组的一部分元素或所有元素,甚至可以创建一个比底层数组还要大的数组切片,因为切片可以动态增长。创建切片的格式如下:
Go
var sliceName [ ]dataType
说明:
切片名的命名规则和变量名相同,遵循标识符命名规则。
在创建切片时,不要指定切片的长度。
切片的类型可以是Go语言的任何基本数据类型。
例如:
var slice1 [] int
上例中定义了一个整型切片slicel,注意不要指定切片长度,如果指定了长度就成了定义数组了。
当一个切片定义好以后,如果还没有被初始化,默认值为nil, 而且切片的长度为0。切片的长度可以使用内置函数len()获取,还可以使用内置函数cap()获取切片的内存容量。
所以,当一个切片定义好以后,还要对切片进行初始化,这样切片才可用。对于上例,假如已经定义了一个整型数组array1,则切片slice1的初始化方式如下:
Go
slice1 = array1[start : end]
从上式可以看到,Go语言支持以array1[start : end]的方式基于一个底层数组来生成切片,即切片引用的数组元素由array1[start]到 array1[end],但不包含array1[end]。
如果要引用底层数组的所有元素,可采取的方式如下:
Go
slicel = array1
slice1 = array1[ :]
slicel = array1[0: len(array1)]
2、直接创建切片
直接创建切片,即在定义切片的时候初始化切片元素,例如:
Go
var slice1 =[]int{1,2,3,4,5}
3、使用make函数创建切片
内置函数make()用于灵活的创建切片
Go
var slicel = make([]int,5)
上式创建了一个有5个元素的整型切片slicel,元素的初值为0。
在使用make()函数创建切片时,还可以为切片元素预留存储空间。例如:
Go
var slice1 = make([]int, 5,10)
上式表示,创建整型切片slice1,元素个数为5,元素初值为0,并预留10个元素的存储空间。
三、切片元素的访问与遍历
切片元素的遍历和数组元素的遍历一样,要通过元素下标访问,另外也可以使用关键字range遍历所有切片元素。
切片元素访问的一般格式如下:
Go
sliceName [sliceIndex]
遍历同数组,使用range关键字表达式,有两个返回值,第一个是元素的下标,第二个是元素的值。
四、切片的操作
1、切片元素的增加
可以使用append()函数向切片尾部添加新元素,这些元素保存到底层数组。append并不会影响原来切片的属性,它返回变更后新的切片对象。
与数组相比,除了都有长度(length)以外,切片多了一个容量(capacity)的概念,即切片中元素的个数和分配的存储空间是两个不同的值。如果在增加新元素时超出cap的限制,则底层会重新分配一块"够大"的内存,一般来说是将原来的内存空间扩大二倍,然后再将数据从原来的内存复制到新的内存块。
2、切片元素的复制
使用切片长时间引用"超大"的底层数组,会导致严重的内存浪费。
可以新建一个小的slice对象,然后将所需的数据复制过去。
函数copy()可以在切片之间复制元素,能够复制的数量取决于复制方和被复制方的长度值,通常取最小值。
需要注意的是,在同一底层数组的不同切片间复制元素时,元素位置会发生重叠。
Go
//切片的复制
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.基本语法
Go
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个斐波那契数列对应的值
Go
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)
的值
Go
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代表天数
Go
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语言中,函数可以作为形参,并且调用
Gopackage 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来定义一个函数类型
Gopackage 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.支持对函数返回值命名
Gopackage 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支持可变参数参数名...,必须放在参数最后位置
Gopackage 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函数
Gopackage main import "fmt" func init() { fmt.Println("init函数自动执行") } func main() { fmt.Println("开始执行主函数") }
-
如果一个文件中同时包含
全局变量
、init函数
、main函数
,则执行顺序为:全局变量 > init > main
Gopackage 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支持匿名函数,如果我们某个函数只希望使用一次,可以考虑使用匿名函数,匿名函数可以实现多次调用
-
示例一:在定义时就调用
Gopackage main import "fmt" func main() { res := func(n1, n2 int) int { return n1 + n2 }(10, 20) fmt.Println("result =", res) }
-
示例二:将匿名函数赋值给一个变量(函数变量),再通过该变量来调用匿名函数
Gopackage main import "fmt" func main() { sum := func(n1, n2 int) int { return n1 + n2 } res := sum(10, 20) fmt.Println("result =", res) }
-
示例三:全匿名函数,将函数赋值给一个全局变量,就成为一个全局函数,可以在程序有效
Gopackage 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、外部函数返回值必须是内嵌函数
-
闭包可以使得变量常驻内存
Gopackage 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
javascriptfunction 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
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
,否则直接返回Gopackage 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语言中被广泛使用,它可以用来表示复杂的数据结构,比如二叉树、链表、图等。
一个简单的结构体定义如下:
Go
copy codetype Person struct {
name string
age int
gender string
}
上面的代码定义了一个名为Person的结构体,它有三个字段,分别是name、age和gender,它们的类型分别为string、int和string。我们可以通过该结构体来表示一个人的基本信息。
1.结构体的语法
Go语言中结构体的语法非常简洁,它的基本形式如下:
Go
copy codetype 结构体名 struct {
字段1 类型1
字段2 类型2
...
字段n 类型n
}
其中,结构体名是用户自定义的标识符,用于表示该结构体的类型。字段是结构体中的成员,每个字段都有一个对应的类型。在定义结构体时,可以使用任何基本类型或其他结构体类型作为字段的类型。另外,结构体中的字段可以使用大写字母开头的标识符表示公有成员,小写字母开头的标识符表示私有成员。
2.结构体的初始化
在Go语言中,结构体类型的变量可以通过结构体字面量来进行初始化。结构体字面量是一种简洁的语法,可以用于快速创建一个结构体类型的变量。
结构体字面量的基本形式如下:
Go
copy codevar 变量名 = 结构体类型{
字段1: 值1,
字段2: 值2,
...
字段n: 值n,
}
其中,变量名是结构体类型的变量名,结构体类型是用户自定义的结构体类型,字段是结构体中的成员,值是该成员对应的初始化值。我们可以省略字段名,只提供值,此时Go语言会按照结构体定义时的字段顺序来进行初始化。例如:
Go
copy codevar p1 = Person{
"张三",
18,
"男",
}
var p2 = Person{
name: "李四",
age: 20,
gender: "女",
}
上面的代码分别创建了两个Person类型的变量p1和p2,它们的字段值分别为{张三 18 男}和{李四 20 女}。可以看出,结构体字面量提供了一种简单、直观的方式来初始化结构体类型的变量。
3.结构体的访问
在Go语言中,可以通过结构体变量的字段名来访问结构体中的成员。例如:
Go
copy codevar p Person
p.name = "张三"
p.age = 18
p.gender = "男"
上面的代码创建了一个名为p的Person类型的变量,并对其成员进行了赋值。可以看出,访问结构体成员的语法非常简单,只需要使用点号(.)连接结构体变量和成员名即可。
4.结构体的方法
Go语言中的结构体还支持方法,方法是一种特殊的函数,它可以与结构体类型关联。方法与函数的区别在于,方法必须在结构体类型上定义,而函数可以在任何地方定义。另外,方法可以访问结构体的成员,而函数只能访问其参数。
Go语言中的方法定义如下:
Go
copy codefunc (接收者变量 接收者类型) 方法名(参数列表) 返回值列表 {
// 方法体
}
其中,接收者变量是一个标识符,用于表示方法所属的结构体类型的变量。接收者类型是方法所属的结构体类型,参数列表和返回值列表与普通函数的定义方式相同。
下面是一个例子:
Go
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语言中,结构体可以嵌套在其他结构体中,从而形成更复杂的数据结构。嵌套结构体的定义方式与普通结构体的定义方式相同,只是在字段的类型中指定另一个结构体类型。
下面是一个例子:
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语言中,结构体还支持匿名字段。匿名字段是一种特殊的字段类型,它没有字段名,只有字段类型。在结构体中,可以使用匿名字段来表示继承关系或者组合关系。
下面是一个例子:
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表示标签的值。
下面是一个例子:
Go
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)功能。
- 网络编程:结构体可以用于表示网络数据包的格式,从而实现网络编程功能。
- 并发编程:结构体可以用于实现并发编程模型,例如管道、锁和条件变量等。
- 配置文件:结构体可以用于表示配置文件的格式,从而实现配置文件读写功能。
- 模板引擎:结构体可以用于表示模板数据,从而实现模板引擎功能。