
知识总结
文章平均质量分 55
精选典型知识点
wohu007
这个作者很懒,什么都没留下…
展开
-
Go 知识点(19)— Go 语言中的野指针
野指针是一种指向内存位置是不可知的指针,一般是由于指针变量在声明时没有初始化所导致的。在 Go语言中,布尔类型的零值为 false,数值类型的零值为 0,字符串类型的零值为 "",而指针、切片、映射、信道、函数和接口的零值则是 nil。nil是 Go 语言中一个预定义的标识符,Go 中的 nil 和其它语言中的 null 有很多不同点:nil 标识符是不能比较的nil 没有默认的类型不同类型的指针是一样的 0x0野指针示例:package mainimport ( "fmt"原创 2021-12-14 22:15:00 · 2801 阅读 · 0 评论 -
Go 知识点(18)— 条件编译(编译标签、文件后缀)
1. 概念在 Go 语言中,可以在源代码里尽量靠源代码文件顶部的地方用注释的方式添加标注,并且标签的结尾添加一个空行,这通常称之为编译标签(build tag)。Go 语言在构建一个包的时候会读取这个包里的每个源文件并且分析编译标签,这些标签决定了这个源文件是否参与本次编译。2. 特点编译标签的四个特征:编译标签由空格分隔的编译选项以逻辑 或的关系组成而编译选项中由逗号分隔的条件项之间是逻辑 与 的关系编译标签的名字由字母 + 数字表示,标签名字前加 ! 表示否定一个文件可以有多个原创 2021-12-09 20:03:21 · 3905 阅读 · 0 评论 -
Go 知识点(17)— go 工具链 go test 使用
package mainimport ( "fmt" "testing")func TestPrint(t *testing.T) { // t.SkipNow() res := Print() if res != 100 { t.Errorf("Return wrong value") }}func TestPrint2(t *testing.T) { res := Print() if res+1 != 101 { t.Errorf("Return wrong原创 2021-09-28 20:51:07 · 484 阅读 · 0 评论 -
Go 知识点(16)— 将枚举值转换为字符串
package mainimport "fmt"type ChipType intconst ( None ChipType = iota CPU GPU)func (c ChipType) String() string { switch c { case None: return "None" case CPU: return "CPU" case GPU: return "GPU" default: return "NA" }}func mai原创 2021-09-26 20:02:28 · 2951 阅读 · 0 评论 -
Go 知识点(15)— 切片长度和容量
1. 切片声明时默认的长度和容量1.1 切片声明时不指定容量切片在使用 make 声明时,如果没有显式的说明切片的容量,那么默认容量和切片的长度保持一致。func main() { s1 := make([]int, 3) fmt.Println("s1 length: ", len(s1)) // s1 length: 3 fmt.Println("s1 capacity: ", cap(s1)) // s1 capacity: 3 fmt.Printf("s1 value: %#v原创 2021-04-19 22:59:05 · 6276 阅读 · 5 评论 -
Go 知识点(14) — Go 多协程(单个协程触发panic会导致其它所有协程挂掉,每个协程只能捕获到自己的 panic 不能捕获其它协程)
在多协程并发环境下,我们常常会碰到以下两个问题。假设我们现在有 2 个协程,我们叫它们协程 A 和 B 。【问题1】如果协程 A 发生了 panic ,协程 B 是否会因为协程 A 的 panic 而挂掉?【问题2】如果协程 A 发生了 panic ,协程 B 是否能用 recover 捕获到协程 A 的 panic ?答案分别是:会、不能。1.【问题1】【问题1】如果协程 A 发生了 panic ,协程 B 是否会因为协程 A 的 panic 而挂掉?package mainim原创 2021-04-18 23:04:05 · 6628 阅读 · 1 评论 -
Go 知识点(13) — 如何判断变量类型
在 Go 语言中可以使用类型断言来判断变量的类型,类型断言的使用有两种方式:返回两个值,分别是断言为设置类型后的值和断言成功的标志符;返回一个值,表示断言为设置类型的值;1. 返回单个值的使用1.1 断言成功如下代码,假如我们无法判断变量 a 的类型,可以使用下面的断言方式func main() { a := []int{1, 2, 3} value := interface{}(a).([]int) fmt.Printf("value is %#v\n", value) // val原创 2021-04-16 22:34:06 · 2680 阅读 · 0 评论 -
Go 知识点(12) — 类型转换以三方库 cast
类型转换在编程语言中是很常见的操作,在 Go 语言中其类型转换有下面一些注意点。1. 整数类型之间的转换对于整数类型转换,原则上目标类型的取值范围要包含被转换值,也就是说要转换类型的值取值范围要小于目标类型的取值范围。如果相反,即目标类型小,而要转换的源值类型大,比如把值的类型从 int16 转换为 int8 ,会出现截断现象,如下代码:func main() { src := int16(-255) dst := int8(src) fmt.Println("dst is ", dst) /原创 2021-04-14 23:05:16 · 466 阅读 · 0 评论 -
Go 知识点(11) — goroutine 泄露、设置子协程退出条件
1. 问题现象如果在开发过程中不考虑 goroutine 在什么时候能退出和控制 goroutine 生命期,就会造成 goroutine 失控或者泄露的情况 ,看示例代码:func consumer(ch chan int) { for { data := <-ch fmt.Println(data) }}func main() { ch := make(chan int) for { var input string // 获取输入,模拟进程持续运行 fmt.原创 2021-04-12 22:06:13 · 692 阅读 · 0 评论 -
Go 知识点(10) — 子协程能否使用主协程变量
我们来看这样一个问题,在主协程中创建的变量,在子协程中能否使用?来看下面代码:func main() { s := "hello" fmt.Printf("s outside address is %v\n", &s) // 0xc0000101e0 var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() s = "world" fmt.Printf("s inside address is %v\n", &a原创 2021-04-11 22:08:50 · 559 阅读 · 0 评论 -
Go 知识点(09)— for select 作用于 channel
1. for select 作用于未关闭的通道1.1 没有 default 分之场景先看下面代码func main() { ch := make(chan int, 3) go func() { time.Sleep(2 * time.Second) // 延迟往通道里里面发送数据 ch <- 1 }() for { select { case v, ok := <-ch: fmt.Printf("v=%v, ok=%v\n", v, ok) time原创 2021-04-10 21:05:27 · 9832 阅读 · 2 评论 -
Go 知识点(08) — 对未初始化的 channel 进行读写操作会造成永久阻塞,对其关闭会触发 panic
1. 对未初始化的 channel 进行写操作先看下面代码func main() { var ch chan int // 只声明,并没有初始化 fmt.Printf("ch is %v\n", ch) // ch is <nil> ch <- 1}运行上述代码,会有如下输出结果:ch is <nil>fatal error: all goroutines are asleep - deadlock!goroutine 1 [c原创 2021-04-09 22:21:36 · 2207 阅读 · 0 评论 -
Go 知识点(07)— 对已经关闭通道进行读写
今天我们来看下对已经关闭通道进行读写会发生什么情况。1. 对已关闭通道进行写操作看下面代码会输出什么结果?func main() { ch := make(chan string, 1) close(ch) ch <- "hello, world" fmt.Println(<-ch)}输出结果为:panic: send on closed channel这个结果无论对于非缓冲通道还是缓冲通道都是一样的,即对已经关闭的通道进行写操作,会触发 panic 。2. 对已关闭原创 2021-04-08 22:15:18 · 2894 阅读 · 0 评论 -
Go 知识点(06)— for range 切片并对切片进行 append 不会造成死循环
想想下面代码会发生什么?func main() { a := []int{1, 2, 3} for _, v := range a { a = append(a, v) fmt.Println("len(a)=", len(a)) } fmt.Printf("a is %#v", a)}会造成死循环吗? 答案是:不会。对于 Go 中的 for ... range 而言,实际上在循环之前就已经获取了切片的长度,然后再执行固定次数的循环,所以上面代码打印结果是:len(a)= 4l原创 2021-04-07 21:39:27 · 733 阅读 · 1 评论 -
Go 知识点(05)— 类型别名与类型定义
1. 类型别名类型别名需要在别名和原类型之间加上赋值符号 = ,使用类型别名定义的类型与原类型等价,Go 语言内建的基本类型中就存在两个别名类型。byte 是 uint8 的别名类型;rune 是 int32 的别名类型;类型别名定义形式如下:type MyString = string上面代码表明 MyString 是 string 类型的别名类型。也就是说别名类型和源类型表示的是同一个目标,就譬如每个人的学名和乳名一样,都表示同一个人。定义 string 类型的别名,示例代码:f原创 2021-04-06 21:59:51 · 1708 阅读 · 2 评论 -
Go 知识点(04)— 结构体字段转 json格式 tag 标签的作用
我们知道在 Go 语言中无论是变量、常量还是函数,对于首字母大小写有不同的处理。首字母大写,标志着该字段或者函数是能导出的,也就是可以被其它包所能访问的;首字母小写,标志着该字段是私有的,只能在本包内使用;同样对于结构体而言也是这样,而结构体里面的字段在转换为 json 对象的时候也存在这个问题。我们看下面代码:type Student struct { id int // 首字母小写、无 tag name string `json:"name"` // 首字母小写、有原创 2021-04-02 22:30:52 · 867 阅读 · 0 评论 -
Go 知识点(03)— 非缓冲 channel 的长度始终为 0
我们先看下面代码输出通道的长度是多少?func main() { ch := make(chan string) go func() { ch <- "hello" close(ch) }() time.Sleep(5 * time.Second) fmt.Println("ch length is ", len(ch)) <-ch}是 1 吗? 答案是: 0, 为什么呢?我们来分析下,首先在主协程中创建了一个通道,然后在子协程中往这个通道中发送内容,发送完毕后关原创 2021-03-31 22:44:48 · 1461 阅读 · 0 评论 -
Go 知识点(02)— channel 使用不当导致的 deadlock
运行下面这段代码输出的结果是什么?package mainimport ( "fmt")func main() { c := make(chan string) // 创建一个无缓冲的通道 c <- "hello world" fmt.Println(<-c)}答案是:会发生死锁fatal error: all goroutines are asleep - deadlock!原因是:对于无缓冲通道,发送方和接收方必须同时准备好才能保证消息的接收。而上面代码发送方原创 2021-03-30 22:24:24 · 672 阅读 · 0 评论 -
Go 知识点(01)— 主协程与子协程执行顺序
下面代码的输出结果是什么?package mainimport ( "fmt") func main() { for i := 0; i < 10; i++ { go func() { fmt.Println(i) }() }}运行该代码输出的结果是什么? 可能有以下答案大概率什么都没有输出原因是: 只要主协程也就是 main 进程执行完毕,其它的 Go 协程就会立即结束,主协程也就是 Go 程序是不会等待其它 Go 协程的,而此时由于 for 循原创 2021-03-29 22:17:04 · 2313 阅读 · 0 评论