差别
这里会显示出您选择的修订版和当前版本之间的差别。
| 两侧同时换到之前的修订记录 前一修订版 | |||
| public:lang:go [2026/05/07 15:10] – 移除 - 外部编辑 (未知日期) 127.0.0.1 | public:lang:go [2026/05/07 15:10] (当前版本) – ↷ 页面public:it:go被移动至public:lang:go oakfire | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| + | ====== Go Lang ====== | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | ===== Tips ===== | ||
| + | * 设置go mod 下载代理:< | ||
| + | go env -w GOPROXY=https:// | ||
| + | |||
| + | ===== 学习笔记 ===== | ||
| + | * 了解该语言的出生背景与适用环境 | ||
| + | * 了解输入输入出流, | ||
| + | * 打印:< | ||
| + | fmt.Println(" | ||
| + | fmt.Printf(" | ||
| + | |||
| + | * 了解程序代码和可执行代码的组织机制,运行时模块加载、符号查找机制 | ||
| + | * 主程序入口 '' | ||
| + | * 包管理,导入包使用 '' | ||
| + | * 包名与导入路径的最后一个元素一致 '' | ||
| + | |||
| + | * 了解该语言的基本数据类型,基本语法和主要语言构造,主要数学运算符和输入输出函数的使用 | ||
| + | * 首字母大写为已导出名 | ||
| + | * 声明时**类型后置**,例如 '' | ||
| + | * 类型相同的声明可只留最后一个,例如 '' | ||
| + | * 变量声明 '' | ||
| + | * 变量声明可有初始值,有初始值时可省略类型:< | ||
| + | * 变量无初始值时将初始为零值'' | ||
| + | * **在函数内时**,变量声明可用'': | ||
| + | * 基本类型:< | ||
| + | string | ||
| + | int int8 int16 int32 int64 | ||
| + | uint uint8 uint16 uint32 uint64 uintptr | ||
| + | byte // uint8 的别名 | ||
| + | rune // int32 的别名 表示一个 Unicode 码点 | ||
| + | float32 float64 | ||
| + | complex64 complex128</ | ||
| + | * 类型转换必须显式转换 '' | ||
| + | var i int = int(f)</ | ||
| + | * 常量定义:'' | ||
| + | * '' | ||
| + | sum += i | ||
| + | } </ | ||
| + | for ; sum < 10; { | ||
| + | sum += sum | ||
| + | }</ | ||
| + | sum := 0 | ||
| + | for sum < 10 { | ||
| + | sum += sum | ||
| + | } | ||
| + | </ | ||
| + | }</ | ||
| + | * '' | ||
| + | if v := math.Pow(2, 10); v < 1000{ | ||
| + | fmt.Println(v) | ||
| + | } else { | ||
| + | fmt.Println(" | ||
| + | } | ||
| + | </ | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | t := time.Now() | ||
| + | switch { | ||
| + | case t.Hour() < 12: | ||
| + | fmt.Println(" | ||
| + | case t.Hour() < 17: | ||
| + | fmt.Println(" | ||
| + | default: | ||
| + | fmt.Println(" | ||
| + | } | ||
| + | </ | ||
| + | * go 拥有指针 '' | ||
| + | * go 结构体 '' | ||
| + | |||
| + | * 了解数组和其他集合类的使用 | ||
| + | * 数组array的声明 '' | ||
| + | * 长度为空时的声明是数组切片,**切片(slice)**可理解为数组部分区间的引用 '' | ||
| + | * 切片拥有 长度'' | ||
| + | * 切片的长度就是它所包含的元素个数。 | ||
| + | * 切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。 | ||
| + | * 切片空值为 '' | ||
| + | * 用 '' | ||
| + | b := make([]int, 0, 5) // len(b)=0, cap(b)=5 | ||
| + | b = b[:cap(b)] // len(b)=5, cap(b)=5 | ||
| + | b = b[1:] // len(b)=4, cap(b)=4 | ||
| + | </ | ||
| + | * 用 '' | ||
| + | * [[https:// | ||
| + | * '' | ||
| + | for i, v := range pow { | ||
| + | fmt.Printf(" | ||
| + | }</ | ||
| + | * map 的声明 '' | ||
| + | * map 赋值 '' | ||
| + | * map 双赋值 <code go> | ||
| + | elem, ok = m[key] | ||
| + | </ | ||
| + | |||
| + | * 了解字符串的处理 | ||
| + | * 字符串库函数[[https:// | ||
| + | * 转换字符串[[https:// | ||
| + | * 了解该语言在面向对象, | ||
| + | * 函数(func)也为值,可传递,可作为参数与返回值 | ||
| + | * 支持函数闭包(Function closures) <code go> | ||
| + | func adder() func(int) int { //< | ||
| + | sum := 0 //< | ||
| + | return func(x int) int { | ||
| + | sum += x | ||
| + | return sum | ||
| + | } | ||
| + | } | ||
| + | |||
| + | func main() { | ||
| + | pos, neg := adder(), adder() | ||
| + | for i := 0; i < 3; i++ { | ||
| + | fmt.Println(pos(i), | ||
| + | } | ||
| + | } | ||
| + | /* 输出 | ||
| + | 0 0 | ||
| + | 1 -2 | ||
| + | 3 -6 | ||
| + | */ | ||
| + | </ | ||
| + | * 没有类的概念,但是可以定义带**reciever**(接收者)的函数作为自定义类型的方法:< | ||
| + | type Vertex struct { | ||
| + | X, Y float64 | ||
| + | } | ||
| + | func (v Vertex) Abs() float64 { // reciever (v Vertex) 放置在 func 与 函数名之间 | ||
| + | return math.Sqrt(v.X*v.X + v.Y*v.Y) | ||
| + | } // 本质上,方法与函数没有区别,即这个方法与 func Abs(v Vertex) float64 没有本质区别,仅仅是可以使用语法糖 v.Abs() | ||
| + | func main() { | ||
| + | v := Vertex{3, 4} | ||
| + | fmt.Println(v.Abs()) | ||
| + | } | ||
| + | </ | ||
| + | * 方法的 reciever 也是值传递,所以如果要修改 reciever 原值,需要把 reciever 定义为指针。在使用指针接收者方法时,默认不需要指针,即 '' | ||
| + | * go 使用 **interface type** (接口类型),接口类型变量可赋值实现了该接口方法的类型的变量,不需要像其它语言需要专门关键字 implement 接口,只要有对应的方法存在即可。fmt 包中定义的 Stringer 是最普遍的接口之一. | ||
| + | * 即便接口的具体值为 nil(接口本身不为nil),方法仍然会正常调用,此时 reciever 为 nil。 | ||
| + | * 指定了零个方法的接口值被称为 **空接口**, | ||
| + | * **type assertion**类型断言:'' | ||
| + | var i interface{} = " | ||
| + | s, ok := i.(string) | ||
| + | fmt.Println(s, | ||
| + | </ | ||
| + | * **type switch**类型选择< | ||
| + | switch v := i.(type) { // 这里 type 为固定关键字 | ||
| + | case T: | ||
| + | // v 的类型为 T | ||
| + | case S: | ||
| + | // v 的类型为 S | ||
| + | default: | ||
| + | // 没有匹配,v 与 i 的类型相同 | ||
| + | } | ||
| + | </ | ||
| + | * 了解特有的语法糖 | ||
| + | * **多值返回**,函数可返回任意数量返回值,也可对返回值命名 '' | ||
| + | * '' | ||
| + | * defer 栈 [[https:// | ||
| + | |||
| + | * 了解该语言错误处理, | ||
| + | * 接口 error; 通常 fmt 包库函数会返回error, | ||
| + | i, err := strconv.Atoi(" | ||
| + | if err != nil { | ||
| + | fmt.Printf(" | ||
| + | return | ||
| + | } | ||
| + | fmt.Println(" | ||
| + | </ | ||
| + | * 了解该语言的内存分配机制或GC, | ||
| + | * **goroutine** 是由 Go 运行时管理的轻量级线程。 | ||
| + | * 信道(**channel**)操作符 ''< | ||
| + | ch := make(chan int, 1) // 创建int值信道, | ||
| + | ch <- v // 将 v 发送至信道 ch。 | ||
| + | v := < | ||
| + | </ | ||
| + | * 发送者可通过 '' | ||
| + | * 接收者可以通过表达式第二个参数来测试信道是否被关闭:若没有值可以接收且信道已被关闭,那么在执行完< | ||
| + | v, ok := < | ||
| + | * 循环 '' | ||
| + | * **select** 语句使一个 goroutine 协程可以等待多个通信操作。select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。如果有 '' | ||
| + | * '' | ||
| + | * 了解该语言的编译/ | ||
| + | ===== 剖析 ===== | ||
| + | |||
| + | * [[http:// | ||
| + | Go 运行时负责调度 Goroutines。Goroutines 的调度是协作式的,而线程不是。 | ||
| + | |||
| + | 这意味着每次一个线程发生切换,你都需要保存/ | ||
| + | |||
| + | 而当另一个 Goroutine 被调度时,只需要保存/ | ||
| + | |||
| + | Go 调度器和任何现代操作 系统的调度器都是 O(1) 复杂度的,这意味着增加线程 /goroutines 的数量不会增加切换时间,但改变寄存器的代价是不可忽视的。 | ||
| + | </ | ||
| + | * [[http:// | ||
| + | * 在Go 1.4 之前, 当创建一个goroutine时,Go运行时会分配一段8K字节的内存用于栈供goroutine运行使用, | ||
| + | * 分段栈(Segmented Stacks)方式, | ||
| + | * 在Go 1.4 中, 使用栈拷贝(stack copying)方式来处理栈伸缩, | ||
| + | * 栈拷贝需把原栈指针重定向, | ||
| + | |||
| + | |||