《The Go Programming Language》第01章 入门

hello world main.go 1 2 3 4 5 6 7 8 9 package main import ( "fmt" ) func main(){ fmt.Println("hello, world") } 编译、生成执行文件、运行: go run main.go 编译: go build main.go 命令行参数 1 2 3 4 5 6 7 8 9 10 11 12 package main import ( "fmt" "os" ) func main(){ for i:=0; i<len(os.Args); i++{ fmt.Println(os.Args[i]) } } 运行命令: go run mian.go a b c...

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《The Go Programming Language》第02章 程序结构

2.1 命名 命名规则 以字母或下划线开头,后面可以跟任意数量的数字,字母,下划线 关键字有25个 1 2 3 4 5 break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var 预定义的名字 1 2 3 4 5 6 7 8 9 10 内建常量: true false iota nil 内建类型: int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex128 complex64 bool byte rune string error 内建函数: make len cap new append copy close delete complex real imag panic recover 作用域 函数内部定义的变量,作用域仅为当前函数内部 在函数外部定义的变量,可以在当前包的所有文件访问 (要设置run on package) 函数外部定义的、大写字母开头的变量(函数),那么它将是导出的(可以被外部的包访问) 2....

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《The Go Programming Language》第03章 基础数据类型

3.1 整型 int8、int16、int32、int64 uint8、uint16、uint32、uint64 两种一般对应特定CPU平台机器字大小的有符号和无符号整数int和uint Unicode字符rune类型是和int32等价的类型 byte和uint8类型是等价类型 无符号的整数类型uintptr 没有指定具体的bit大小但是足以容纳指针 uintptr类型只有在底层编程时才需要 运算 %取模运算符的符号和被取模数的符号总是一致的,因此-5%3和-5%-3结果都是-2。 除法运算符/的行为则依赖于操作数是否全为整数,比如5.0/4.0的结果是1.25,但是5/4的结果是1 对于整数,+x是0+x的简写,-x则是0-x的简写; 内置的len函数返回一个有符号的int 打印方法 用%d、%o或%x参数控制输出的进制格式 fmt.Printf("%d %[1]x %#[1]x %#[1]X\n", x) %之后的[1]副词告诉Printf函数再次使用第一个操作数 3.2 浮点数 float32和float64 浮点数的范围极限值可以在math包找到 math.MaxFloat32表示float32能表示的最大数值,大约是 3.4e38; math.MaxFloat64常量大约是1.8e308。它们分别能表示的最小值近似为1.4e-45和4.9e-324 打印方法 用Printf函数的%g参数打印浮点数,将采用更紧凑的表示形式打印,并提供足够的精度,但是对应表格的数据 使用%e(带指数)或%f的形式打印可能更合适。 所有的这三个打印形式都可以指定打印的宽度和控制打印精度。 fmt.Printf("x = %d e^x = %8.3f\n", x, math.Exp(float64(x))) 3.3 复数 complex64和complex128 3.4 布尔型 3.5 字符串 一个字符串是一个不可改变的字节序列 s[0] = 'L' // compile error: cannot assign to s[0] 第i个字节并不一定是字符串的第i个字符,因为对于非ASCII字符的UTF8编码会要两个或多个字节 一个原生的字符串面值形式是....

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《The Go Programming Language》第04章 复合数据类型

数组 默认情况下,数组的每个元素都被初始化为元素类型对应的零值 如果在数组的长度位置出现的是“…”省略号,则表示数组的长度是根据初始化值的个数来计算 数组的长度是数组类型的一个组成部分,因此[3]int和[4]int是两种不同的数组类型 定义了一个含有100个元素的数组r,最后一个元素被初始化为-1,其它元素都是用0初始化。 r := [...]int{99: -1} 如果一个数组的元素类型是可以相互比较的,那么数组类型也是可以相互比较的,支持==和!= 当调用一个函数的时候,函数的每个调用参数将会被赋值给函数内部的参数变量,所以函数参数变量接收的是一个复制的副本,并不是原始调用的变量。 数组依然很少用作函数参数;相反,我们一般使用slice来替代数组。 Slice 一个slice由三个部分构成:指针、长度和容量 内置的len和cap函数分别返回slice的长度和容量。 多个slice之间可以共享底层的数据,并且引用的数组部分区间可能重叠 x[m:n]切片操作对于字符串则生成一个新字符串,如果x是[]byte的话则生成一个新的[]byte。 slice将允许在函数内部修改底层数组的元素 slice之间不能比较,因此我们不能使用==操作符来判断两个slice是否含有全部相等元素 标准库提供了高度优化的bytes.Equal函数来判断两个字节型slice是否相等([]byte),但是对于其他类型的slice,我们必须自己展开每个元素进行比较 Map 它是一个无序的key/value对的集合 在Go语言中,一个map就是一个哈希表的引用 key必须是支持==比较运算符的数据类型 不建议将浮点数作为key值 创建map的几种方法: 1 2 3 4 5 6 7 8 ages := make(map[string]int) ages = map[string]int{ "cat": 321, "dog": 123 } ages = map[string]int{} 删除:delete(ages, "cat") map中的元素并不是一个变量,所以不能进行取地址操作&。原因是扩容导致地址失效 Map的迭代顺序是不确定的 判断元素是否存在于map中的写法 1 2 3 if cat, ok := ages["cat"]; !...

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《The Go Programming Language》第05章 函数

函数声明 函数声明的格式: 1 2 3 func name(parameter-list) (result-list) { body } 如果函数返回一个无名变量或者没有返回值,返回值列表的括号是可以省略的 如果一个函数声明不包括返回值列表,那么函数体执行完毕后,不会返回任何值 参数 Go语言没有默认参数值,也没有任何方法可以通过参数名指定形参,因此形参和返回值的变量名对于函数调用者而言没有意义。 在函数体中,函数的形参作为局部变量,被初始化为调用者提供的值。函数的形参和有名返回值作为函数最外层的局部变量,被存储在相同的词法块中。 实参通过值的方式传递,因此函数的形参是实参的拷贝。对形参进行修改不会影响实参。但是,如果实参包括引用类型,实参可能会由于函数的间接引用被修改。 函数签名 不定义函数体即可 例如:func Sin(x float64) float //implemented in assembly language 递归 多返回值 func Size(rect image.Rectangle) (width, height int) bare return 函数声明是声明多个返回值,在函数体中return时可以只写return,默认返回声明中的变量 使用bare return可以不用在return时再次声明返回值(但这样容易出错) 错误 内置的error是接口类型 打印error可以获得稍微详细一点的错误信息 go error设计哲学 在Go中,函数运行失败时会返回错误信息,这些错误信息被认为是一种预期的值而非异常(exception) 虽然Go有各种异常机制,但这些机制仅被使用在处理那些未被预料到的错误,即bug,而不是那些在健壮程序中应该被避免的程序错误。 Go使用控制流机制(如if和return)处理错误,这使得编码人员能更多的关注错误处理 函数值 在go中,函数被看作是第一类值(first-class values),函数拥有类型,可以被赋值给其他变量,传递给函数,从函数返回,例如 1 2 3 4 5 6 7 8 9 10 11 func forEachNode(n *html....

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《The Go Programming Language》第06章 方法

方法声明 在函数声明时,在其名字之前放上一个变量,即是一个方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package main import ( "fmt" ) type Point struct{ x, y float64 } func (p Point) dist(q Point)float64{ dx := p.x - q.x dy := p.y - q.y return dx*dx + dy*dy } func main(){ var p Point = Point{x: 1, y: 2} var q Point = Point{x: 3, y: 4} fmt....

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《The Go Programming Language》第07章 接口

接口类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package main import "fmt" type People struct { } type speaker interface { say(content string) string } func (p *People) say(content string) string{ return "people say: " + content } func main(){ var p People var s speaker s = &p // 注意取地址符 fmt.Println(s.say("I love you")) } 实现接口的条件 接口A可以赋值给接口B,前提是接口B实现了接口A的某些方法 空接口类型interface{}: 任意类型都可以被空接口赋值 接口值 接口值由两部分组成: 具体的类型(动态类型) 该类型的值(动态值) 一个接口的零值就是它的类型和值的部分都是nil 在go中,类型是编译期的概念,因此类型不是一个值。...

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《The Go Programming Language》第08章 goroutine和channel

goroutine 形如: go + function 1 2 3 4 5 6 7 8 func f(){ for i:=1; i<100; i++{ fmt.Println(i); } } go f() channel 声明一个channel 1 2 3 ch := make(chan int, 0) // 双向channel, 无缓冲 ch := make(chan<- int, 0) // 单向channel,只接收 ch := make(<-chan int, 0) // 单向channel,只发送 操作channel 1 2 3 ch <- x // 将x写入channel ch x, ok = <- ch // 从ch中读取数据,放入x。 ok判断是否正常获取 <- ch // 读取数据并抛弃 关闭channel 1 close(ch) // 关闭channel 对一个关闭了的channel发送信息,将产生panic 从一个关闭了的channel读取数据,可以读取其中剩余的(只是不能再写入) 问题1: 读取关闭了的channel会怎样?...

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀