You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 lines
7.3 KiB
XML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>语言特性 on 深入Go语言之旅</title>
<link>https://go.cyub.vip/feature/</link>
<description>Recent content in 语言特性 on 深入Go语言之旅</description>
<generator>Hugo -- gohugo.io</generator>
<language>zh-cn</language><atom:link href="https://go.cyub.vip/feature/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>for-range语法</title>
<link>https://go.cyub.vip/feature/for-range/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://go.cyub.vip/feature/for-range/</guid>
<description>遍历 - for-range语法 # for-range语法可以用来遍历数组、指向数组的指针切片、字符串、映射和通道。
遍历数组 # 当遍历一个数组a时候循环范围会从0到len(a) -1
func main() { var a [3]int for i, v := range a { fmt.Println(i, v) } for i, v := range &amp;amp;a { fmt.Println(i, v) } } 遍历切片 # 当遍历一个切片s时候循环范围会从0到len(s) -1若切片是nil则迭代次数是0次
func main() { a := make([]int, 3) for i, v := range a { fmt.Println(i, v) } a = nil for i, v := range a { fmt.Println(i, v) } } for-range切片时候可以边遍历边append吗 # 当遍历切片时候可以边遍历边append操作这并不会造成死循环。因为遍历之前已经确定了循环范围遍历操作相当如下伪代码</description>
</item>
<item>
<title>panic与recover机制</title>
<link>https://go.cyub.vip/feature/panic-recover/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://go.cyub.vip/feature/panic-recover/</guid>
<description>恐慌与恢复 - panic/recover # 我们知道Go语言中许多错误会在编译时暴露出来直接编译不通过但对于空指针访问元素切片/数组越界访问之类的运行时错误,只会在运行时引发 panic 异常暴露出来。这种由Go语言自动的触发的 panic 异常属于运行时panic(Run-time panics)1。当发生 panic 时候Go会运行所有已经注册的延迟函数若延迟函数中未进行panic异常捕获处理那么最终Go进程会终止并打印堆栈信息。此外Go中还内置了 panic 函数可以用于用户手动触发panic。
Go语言中内置的 recover 函数可以用来捕获 panic异常但 recover 函数只能放在延迟函数调用中,才能起作用。我们从之前的章节《 基础篇-语言特性-defer函数 》了解到多个延迟函数会组成一个链表。Go在发生panic过程中会依次遍历该链表并检查链表中的延迟函数是否调用了 recover 函数调用,若调用了则 panic 异常会被捕获而不会继续向上抛出,否则会继续向上抛出异常和执行延迟函数,直到该 panic 没有被捕获进程异常终止这个过程叫做panicking。我们需要知道的是即使panic被延迟函数链表中某个延迟函数捕获处理了但其他的延迟函数还是会继续执行的只是panic异常不在继续抛出。
接下来我们来将深入了解下panic和recover底层的实现机制。在开始之前我们来看下下面的测试题。
测试题下面哪些panic异常将会捕获 # case 1:
func main() { recover() panic(&amp;#34;it is panic&amp;#34;) // not recover } case 2:
func main() { defer func() { recover() }() panic(&amp;#34;it is panic&amp;#34;) // recover } case 3:
func main() { defer recover() panic(&amp;#34;it is panic&amp;#34;) // not recover } case 4:</description>
</item>
<item>
<title>延迟执行 - defer语法</title>
<link>https://go.cyub.vip/feature/defer/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://go.cyub.vip/feature/defer/</guid>
<description>延迟执行 - defer语法 # defer 语法支持是Go 语言中一大特性,通过 defer 关键字,我们可以声明一个延迟执行函数,当调用者返回之前开始执行该函数,一般用来完成资源、锁、连接等释放工作,或者 recover 可能发生的panic。
三大特性 # defer延迟执行语法有三大特性
defer函数的传入参数在定义时就已经明确 # func main() { i := 1 defer fmt.Println(i) i++ return } 上面代码输出1而不是2。
defer函数是按照后进先出的顺序执行 # func main() { for i := 1; i &amp;lt;= 5; i++ { defer fmt.Print(i) } } 上面代码输出54321而不是12345。
defer函数可以读取和修改函数的命名返回值 # func main() { fmt.Println(test()) } func test() (i int) { defer func() { i++ }() return 100 } 上面代码输出输出101而不是100或者1。
白话defer原理 # defer函数底层数据结构是_defer结构体多个defer函数会构建成一个_defer链表后面加入的defer函数会插入链表的头部该链表链表头部会链接到G上。当函数执行完成返回的时候会从_defer链表头部开始依次执行defer函数。这也就是defer函数执行时会LIFO的原因。_defer链接结构示意图如下</description>
</item>
<item>
<title>逗号ok模式</title>
<link>https://go.cyub.vip/feature/comma-ok/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://go.cyub.vip/feature/comma-ok/</guid>
<description> 逗号ok模式 # 通过逗号ok模式(comma ok idiom)我们可以进行类型断言判断映射中是否存在某个key以及通道是否关闭。
类型断言 # // 方式1 var ( v T ok bool ) v, ok = x.(T) // 方式2 v, ok := x.(T) // x是接口类型的变量T是要断言的类型 // 方式3 var v, ok = x.(T) // 方式4 v := x.(T) // 当心此种方式断言,若断言失败会发生恐慌 判断key是否存在映射中 # // 方式1 v, ok := a[x] // 方式2 var v, ok = a[x] 判断通道是否关闭 # // 方式1 var ( x T ok bool ) x, ok = &amp;lt;-ch // 方式2 x, ok := &amp;lt;-ch // 方式3 var x, ok = &amp;lt;-ch </description>
</item>
<item>
<title>通道选择器-select</title>
<link>https://go.cyub.vip/feature/select/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://go.cyub.vip/feature/select/</guid>
<description>通道选择器-select # Go 语言中select关键字结构跟switch结构类似但是select结构的case语句都是跟通道操作相关的。Go 语言会从select结构中已经可读取或可以写入通道对应的case语句中随机选择一个执行如果所有case语句中的通道都不能可读取或可写入且存在default语句的话那么会执行default语句。
根据Go 官方语法指南指出select语句执行分为以下几个步骤
For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the &amp;ldquo;select&amp;rdquo; statement. The result is a set of channels to receive from or send to, and the corresponding values to send. Any side effects in that evaluation will occur irrespective of which (if any) communication operation is selected to proceed.</description>
</item>
</channel>
</rss>