x
关闭自动补全
ctrl+Alt+s
在设置窗口中,导航到:Editor → General → Code Completion。
在设置窗口中,导航到:Editor → General → Code Completion。
inline最上方关闭
strconv
用于字符串和基本数据类型之间进行相互转换
1 | package main |
带初始化语句的if写法
1 | import "fmt" |
给score赋值85,然后进if判断,这个score变量作用域只在if判断内部,外界无法访问
Fields
把字符串按空白字符(空格,换行符,制表符)分割成一个字符串切片
1 | package main |
fmt.PrintIn打印字符串类型不加引号
要想显示引号用
1 | fmt.Printf("%q\n", words)//["go" "is" "fun"] |
%q给字符串加引号,安全转义
%#v输出值的Go语法表示
运算时必须强制类型转换
否则报错
1 | invalid operation: a + b (mismatched types int and float64) |
1 | func main() { |
for循环与切片
1 | import ( |
for循环遍历切片words,每次循环返回两个值(索引和元素值)
range基本上都返回两个值
空标识符忽略索引,用word接收当前遍历到的单词
freq是一个映射或字典,键是单词,值是出现次数
freq[word]++
我不理解
函数与错误处理
1 | for index , value :=range nums 会返回索引和元素值 |
1 | func divide(a, b float64) (float64, error) { |
闭包
看不懂定义,我觉得闭包就是函数的返回值依旧是函数,像一个带记忆的自动机器
1 | func counter() func() int { |
返回
1 | 1 |
数组,切片映射
1 | func main() { |
1 | 赋值前 [1 2 3] |
他还会自动排个序
结构体与方法
1 | type Rectangle struct { |
接口
接口定义了一组方法签名,定义了方法名称,参数类型,返回值类型,但不包含具体实现
隐式实现意味着不需要像java一样显式声明那个接口
只要一个类型拥有接口要求的所有方法,它就自动实现了该接口。这称为鸭子类型(“如果它走路像鸭子,叫声像鸭子,那它就是鸭子”)。
1 | type Speaker interface { |
多态:一个接口变量可以持有不同类型的值
错误处理
1 | func checkAge(age int) error { |
指针
*T 表示指向 T 的指针类型
& 取地址,* 解引用
指针允许函数修改外部变量
零值为 nil
1 | func zeroVal(Val int) { |
并发
go 关键字 启动一个轻量级线程(goroutine)
channel用于goroutine间通信 ch:=make(chan type)
goroutine是GO运行时管理的用户态线程,比操作系统线程轻量得多
Goroutine
1 | func sayHello() { |
1 | slice[low:high] // 从 low 索引开始,到 high-1 索引结束,长度为 high-low |
1 | func say(s string) { |
两个 say 函数几乎同时运行。go 关键字让函数在独立 goroutine 中异步执行。
channel有发送和接收操作,用于goroutine之间安全地传递数据
channel
的range只接受一个值
1 | c chan int |
1 | make(chan int) |
1 | make(chan int,100) |
通道缓冲区
用于临时存储数据的一段内存空间,当缓冲区大小为0时,发送和接收必须同时就绪,否则阻塞,是同步通信
没缓冲区的发完必须马上写一个接收的动作,有缓冲区的发完一个可以再发一个,直到填满缓冲区容量,然后一次性接收
1 | func worker(id int, jobs <-chan int, result chan<- int) { //jobs只从channel读,results只从channel写 |
1 | func sum(s []int, c chan int) { |
go遍历通道与关闭通道
1 | cap(x) |
1 | func fibonacci(n int, c chan int) { |
select
用于处理多个通道操作的控制结构,每个case必须是一个通道的发送或接受操作
用于同时等待多个 channel 操作,类似于 switch 但专门用于 channel。
WaitGroup
等待·一组goroutine完成
启动5个goroutine,每个打印自己的序号,确保主函数等待所有goroutine完成
1 | func main() { |
使用无缓冲channel实现两个goroutine交替打印1-10
1 | func main() { |
1 | x:= <-ch //接收并赋值给x |
带缓冲channel实现简单队列
创建容量为3的缓冲channel,启动3个worker从channel中消费整数并打印,主线程发送10个数字后关闭channel
1 | func woker(id int, jobs <-chan int, wg *sync.WaitGroup) { |
使用Mutex保护共享计数器
100个goroutine同时对一个共享变量加1,每个加1000次,最终结果应为100000,用互斥锁保证正确性
1 | func main() { |
select实现超时控制
模拟一个可能执行很久的操作,如果2秒内未完成则输出超时
1 | func main() { |
依然回显timeout
研究一下
原因有
-
线程启动延迟
-
Windows默认时钟精度为15ms time.Sleep(1999ms)实际可能向上取整
-
通道发送阻塞,finish在写入done前要res先准备好接收,所以有延迟
验证一下
代码前后打上时间戳
1 | func main() { |
和一位,这会结果又是finish,重复几次还是finish
1 | goroutin started at 507.8µs |
1 | goroutin started at 0s |
这超过了还是判断为finish
还是太闲了
Context(控制线程的生命周期)取消线程
启动一个监控线程不断打印working。。。
主程序3秒后通过context取消
1 |
sync包
atomic包
Context
函数和方法
函数和方法居然不是同一个东西
方法是绑定了结构体的函数
制作端口扫描小工具
1 | time.Duriation |
1 | timeout time.Duriation |
1 | net.JoinHostPost() |
可执行程序必须使用package
any
类型别名,完全等同于 interface{}。
表示可以是任何类型
defer func() { _ = recover() }()
Go 内置函数,用于捕获 panic,只在 defer 函数中有效。
1 | // 完整示例 |
如有错误,多多指教