public:it:go

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
public:it:go [2021/12/10 13:34] – [学习笔记] oakfirepublic:it:go [2022/11/10 12:37] (当前版本) – [Go Lang] oakfire
行 3: 行 3:
   * [[https://pkg.go.dev/std|标准库文档]]   * [[https://pkg.go.dev/std|标准库文档]]
   * [[https://go.dev/ref/spec|go 编程语言规范]]   * [[https://go.dev/ref/spec|go 编程语言规范]]
 +  * [[https://github.com/LearnGolang/LearnGolang|Golang 学习资源大全]]
  
 ===== 学习笔记 ===== ===== 学习笔记 =====
行 95: 行 96:
  
   * 了解字符串的处理   * 了解字符串的处理
 +    * 字符串库函数[[https://go-zh.org/pkg/strings/|strings]]
 +    * 转换字符串[[https://go-zh.org/pkg/strconv/|strconv]], [[https://go-zh.org/pkg/fmt/#Sprint|fmt.Sprint, fmt.Sprintf, fmt.Sprintln]]
   * 了解该语言在面向对象,函数式编程,泛型,元编程等编程范式的特性   * 了解该语言在面向对象,函数式编程,泛型,元编程等编程范式的特性
     * 函数(func)也为值,可传递,可作为参数与返回值     * 函数(func)也为值,可传递,可作为参数与返回值
 +    * 支持函数闭包(Function closures) <code go>
 +func adder() func(int) int { //<oak>: 这类型后置也有点绕眼
 +    sum := 0  //<oak>: 这sum的作用域也有点绕脑
 +    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), neg(-2*i))
 +    }
 +}
 +/* 输出
 +0 0
 +1 -2
 +3 -6
 +*/
 +</code>
 +    * 没有类的概念,但是可以定义带**reciever**(接收者)的函数作为自定义类型的方法:<code go>
 +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())
 +}
 +</code>只能为在同一包内定义的类型的接收者声明方法,而不能为其它包内定义的类型(包括 int 之类的内建类型)的接收者声明方法。
 +    * 方法的 reciever 也是值传递,所以如果要修改 reciever 原值,需要把 reciever 定义为指针。在使用指针接收者方法时,默认不需要指针,即 ''v.scale()'' 等效于 ''(&v).scale()'';反过来也成立,对于指针''p := &v'', ''p.Abs()'' 等效于 ''(*p).Abs()''
 +    * go 使用 **interface type** (接口类型),接口类型变量可赋值实现了该接口方法的类型的变量,不需要像其它语言需要专门关键字 implement 接口,只要有对应的方法存在即可。fmt 包中定义的 Stringer 是最普遍的接口之一.
 +    * 即便接口的具体值为 nil(接口本身不为nil),方法仍然会正常调用,此时 reciever 为 nil。
 +    * 指定了零个方法的接口值被称为 **空接口**, 空接口可赋予任意类型的值,可用来处理未知类型的值
 +    * **type assertion**类型断言:''t := i.(T)'' 或 '' t, ok := i.(T)'',判断一个接口值是否保存了一个特定的类型<code go>
 +var i interface{} = "hello"
 +s, ok := i.(string)
 +fmt.Println(s, ok) // hello true
 +</code>
 +    * **type switch**类型选择<code go>
 +switch v := i.(type) {  // 这里 type 为固定关键字
 +case T:
 +    // v 的类型为 T
 +case S:
 +    // v 的类型为 S
 +default:
 +    // 没有匹配,v 与 i 的类型相同
 +}
 +</code>
   * 了解特有的语法糖   * 了解特有的语法糖
     * **多值返回**,函数可返回任意数量返回值,也可对返回值命名 ''func split(sum int) (x, y int)'',没有参数的 ''return'' 语句返回已命名的返回值。     * **多值返回**,函数可返回任意数量返回值,也可对返回值命名 ''func split(sum int) (x, y int)'',没有参数的 ''return'' 语句返回已命名的返回值。
行 103: 行 158:
  
   * 了解该语言错误处理,调试方式以及对测试的支持   * 了解该语言错误处理,调试方式以及对测试的支持
 +    * 接口 error; 通常 fmt 包库函数会返回error, error 为 nil 时表示成功;非 nil 的 error 表示失败 <code go>
 +i, err := strconv.Atoi("42"
 +if err != nil {
 +    fmt.Printf("couldn't convert number: %v\n", err)
 +    return
 +}
 +fmt.Println("Converted integer:", i)
 +</code>
   * 了解该语言的内存分配机制或GC,线程,进程等运行时效率相关   * 了解该语言的内存分配机制或GC,线程,进程等运行时效率相关
 +    * **goroutine** 是由 Go 运行时管理的轻量级线程。
 +    * 信道(**channel**)操作符 ''<-'' <code go>
 +ch := make(chan int, 1) // 创建int值信道, 第二个参数为缓冲区大小
 +ch <- v    // 将 v 发送至信道 ch。
 +v := <-ch  // 从 ch 接收值并赋予 v
 + </code>信道缓冲区(默认1)满时阻塞发送端,空时阻塞接收端。这让 goroutine 可以在没有显式的锁或竞态变量的情况下进行同步。
 +    * 发送者可通过 ''close'' 关闭一个信道,只有发送者可关闭信道。
 +    * 接收者可以通过表达式第二个参数来测试信道是否被关闭:若没有值可以接收且信道已被关闭,那么在执行完<code>
 +v, ok := <-ch</code>之后 ''ok'' 会被设置为 ''false''
 +    * 循环 ''for i := range ch'' 会不断从信道接收值,直到它被关闭
 +    * **select** 语句使一个 goroutine 协程可以等待多个通信操作。select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。如果有 ''default'', 则在所有分支阻塞时执行 default。
 +    * ''sync.Mutex'' 互斥锁
   * 了解该语言的编译/解释机制   * 了解该语言的编译/解释机制
 ===== 剖析 ===== ===== 剖析 =====
  • public/it/go.1639114467.txt.gz
  • 最后更改: 2021/12/10 13:34
  • oakfire