Go语言-结构体里的Tag标签
第 23 章 结构体里的 Tag 标签在之前结构体的章节里我们讲过结构体的使用,一般情况下,我们定义结构体每个字段都是由字段名字以及字段的类型构成,例如:
12345type Book struct { Name string Target string Spend int}
23.1 Tag 的使用但这一章要讲的是在字段上增加一个属性,这个属性是用反引号括起来的一个字符串,我们称之为 Tag(标签) 。例如:
12345type Person struct { Name string `json:"name"` Target string `json:"target"` Spend int `json:"spend,omitempty"`}
结构体的 Tag 可以是任意的字符串面值,但是通常是一系列用空格分隔的 key:"value" 键值对序列;因为值中含有双引号字符,因此成员 Tag 一般用原生字符串面值 ...
Go语言-反射
第 22 章节 反射22.1 reflect 包Go 语言提供了一种机制,能够在运行时更新变量和检查它们的值、调用它们的方法,而不需要在编译时就知道这些变量的具体类型。这种机制被称为 反射 。
反射是把双刃剑,功能强大但代码可读性并不理想,若非必要并不推荐使用反射。
在 Go 中 reflect 包实现了运行时反射。reflect 包会帮助识别 interface{} 变量的底层具体类型和具体值。
22.1.1 reflect.Typereflect.Type 表示 interface{} 的具体类型。reflect.TypeOf() 方法返回 reflect.Type 。
像我们之前讲过的空接口参数的函数,可以通过类型断言来判断传入变量的类型,也可以借助反射来确定传入变量的类型。
123456789101112131415161718package mainimport ( "fmt" "reflect")func reflectType(x interface{}) ...
Go语言-静态类型与动态类型
第 21 章 静态类型与动态类型21.1 静态类型(static type)静态类型就是变量声明时候的类型。例如:
1234// int 是静态类型var number int// string 也是静态类型var name string
21.2 动态类型(concrete type)动态类型是程序运行时系统才能看见的类型。例如:
123456// in 的静态类型为 interface{}var in interface{}// in 的静态类型为 interface{} 动态类型为 intin = 100// in 的静态类型为 interface{} 动态类型为 stringin = "《从0到Go语言微服务架构师训练营》"
通过上面的例子,可以看到我们定义了一个空接口 in ,它的静态类型永远是 interface{} ,但它可以接受任何类型,接受整型数据时,它的动态类型就为 int ;接受字符串型数据时,它的动态类型就变为 string 。
21.3 ...
Go语言-函数是一等公民
第 20 章 头等函数Go 语言拥有 头等函数(First-class Function) ,头等函数是指函数可以被当作变量一样使用,即函数可以被当作参数传递给其他函数,可以作为另一个函数的返回值,还可以被赋值给一个变量。
20.1 把函数赋值给变量下面是一个把函数赋值给变量的例子,该函数没有名称,调用该函数的唯一方法就是使用赋值后的变量。
1234567891011package mainimport "fmt"func main() { bookFunc := func() { fmt.Println("《Go语言极简一本通》") } bookFunc() fmt.Printf("bookFunc 的类型是 %T\n", bookFunc)}
运行该程序输出如下:
12《Go语言极简一本通》bookFunc 的类型是 func()
20.2 传递一个函数作为参数我们把 接收一个或多个函数作为参数 或者 返回值也是一个函数 的函数称为 高阶函数 ...
Go语言-make和new
第 19 章 make 和 new内置函数 new 分配内存。该函数只接受一个参数,该参数是一个任意类型(包括自定义类型),而不是值,返回指向该类型新分配零值的指针。
1234// The new built-in function allocates memory. The first argument is a type,// not a value, and the value returned is a pointer to a newly// allocated zero value of that type.func new(Type) *Type
使用 new 函数首先会分配内存,并设置类型零值,最后返回指向该类型新分配零值的指针。
1234567891011package mainimport ( "fmt")func main() { num := new(int) // 打印出类型的值 fmt.Println(*num) // 0}
19.1 make 函数内置函数 make 只能分配和初始化类型为 slice 、 ma ...
Go语言-错误与异常
第 18 章 错误与异常18.1 错误18.1.1 内建错误在 Go 中, 错误 使用内建的 error 类型表示。error 类型是一个接口类型,它的定义如下:
123type error interface { Error() string}
error 有了一个签名为 Error() string 的方法。所有实现该接口的类型都可以当作一个错误类型。Error() 方法给出了错误的描述。fmt.Println 在打印错误时,会在内部调用 Error() string 方法来得到该错误的描述。
下面的例子演示了程序尝试打开一个不存在的文件导致的报错:
123456789101112131415161718package mainimport ( "fmt" "os")func main() { // 尝试打开文件 file, err := os.Open("/a.txt") // 如果打开文件时发生错误 返回一个不等于 nil 的错误 if err ...
Go语言-线程同步
第 17 章 线程同步在 Go 语言中,经常会遇到并发的问题,当然我们会优先考虑使用通道,同时 Go 语言也给出了传统的解决方式 Mutex(互斥锁) 和 RWMutex(读写锁) 来处理竞争条件。
12345678910111213141516171819202122type Bank struct { balance int}func (b *Bank) Deposit(amount int) { b.balance += amount}func (b *Bank) Balance() int { return b.balance}func main() { b := &Bank{} b.Deposit(1000) b.Deposit(1000) b.Deposit(1000) fmt.Println(b.Balance()) //3000}
17.1 临界区首先我们要理解并发编程中临界区的概念。当程序并发地运行时,多个 G ...
Go语言-Select
第 16 章 Selectselect 语句用在多个发送/接收通道操作中进行选择。
select 语句会一直阻塞,直到发送/接收操作准备就绪。
如果有多个通道操作准备完毕, select 会随机地选取其中之一执行。
select 语法如下:
12345678select { case expression1: code case expression2: code default: code}
下面是使用 select-case 的一个简单例子:
12345678910111213141516171819202122232425262728293031package mainimport "fmt"func main() { // 创建3个通道 ch1 := make(chan string, 1) ch2 := make(chan string, 1) ch3 := make(chan string, 1) // 往通道 ...
Go语言-通道
第 15 章 channel 通道通道(channel) ,就是一个管道,可以想像成 Go 协程之间通信的管道。它是一种队列式的数据结构,遵循先入先出的规则。
15.1 通道的声明每个通道都只能传递一种数据类型的数据,在你声明的时候,我们要指定通道的类型。chan Type 表示 Type 类型的通道。通道的零值为 nil 。
1var channel_name chan channel_types
下面的语句声明了一个类型为 string 的通道 nameChan ,该通道 nameChan 的值为 nil 。
1var ch chan string
15.2 通道的初始化声明完通道后,通道的值为 nil ,我们不能直接使用,必须先使用 make 函数对通道进行初始化操作。
1ch = make(chan channel_type)
使用下面的语句我们可以对上面声明过的通道 ch 进行初始化:
1ch = make(chan string)
这样,我们就已经定义好了一个 string 类型的通道 nameChan 。当然,也可以使用简短声明语句一次性定义一个通道:
1ch : ...
Go语言-协程
第 14 章 go 协程Go 语言的 协程(Groutine) 是与其他函数或方法一起并发运行的工作方式。协程可以看作是轻量级线程。与线程相比,创建一个协程的成本很小。因此在 Go 应用中,常常会看到会有很多协程并发地运行。
14.1 启动一个 go 协程调用函数或者方法时,如果在前面加上关键字 go ,就可以让一个新的 Go 协程并发地运行。
12345678910// 定义一个函数func functionName(parameterList) { code}// 执行一个函数functionName(parameterList)// 开启一个协程执行这个函数go functionName(parameterList)
下面是启动一个协程的例子, go PrintInfo() , PrintInfo() 函数与 main() 函数会并发执行,主函数运行在一个特殊的协程上,这个协程称之为 主协程(Main Goroutine) 。
启动一个新的协程时,协程的调用会立即返回。与函数不同,程序控制不会去等待 Go 协程执行完毕。在调用 Go 协程之后,程序控制 ...