做网站公司上班违法吗,青岛seo经理,烟台网站建设地址,valenti wordpress学习笔记 —— Go 指南 前言#xff1a;先贴上网址#xff0c;因为是先用 Typora 写#xff0c;然后直接导入的#xff0c;所以格式多多少少有点问题 文章目录学习笔记 —— Go 指南一. 包、变量和函数二. 流程控制语句 for、switch、if 和 defer三. 更多类型 struct、sli…学习笔记 —— Go 指南 前言先贴上网址因为是先用 Typora 写然后直接导入的所以格式多多少少有点问题 文章目录学习笔记 —— Go 指南一. 包、变量和函数二. 流程控制语句 for、switch、if 和 defer三. 更多类型 struct、slice 和映射四. 方法和接口五. 并发一. 包、变量和函数 导包可以用分组形式括号 import (fmtmath
)在 Go 中如果一个名字以大写字母开头那么它就是已导出的。 math.pi // 未导出的变量无法访问
math.Pi 函数参数类型在后连续同类型时可以省略只在最后一个参数写上类型 func add(x, y int) int {return x y
}多值返回函数可以返回任意数量的返回值。 func swap(x, y string) string {return y, x
}返回值可被命名位于函数顶部。 无参的 return 语句会直接返回已命名的返回值。长函数这样使用会影响可读性 // 已命名返回值 x, y
func split(sum int) (x, y int) {x sum % 10;y sum / 10;// 会返回 x, yreturn
} var 语句用于声明一个变量列表跟函数的参数列表一样类型在最后。 var 语句可以出现在包或函数级别。 package mainimport fmtvar java, python, golang bool
func main(){var i intfmt.Println(i, java, python, golang)
}声明可以包含初始化值 有初始化值时可以省略类型会从初始化值中自动获取。 var i, j int 1, 3
// 自动获取可以类型不同
var golang, java true, java~短变量声明在函数中可以用 “:” 来代替 var 声明语句。函数外不行因为函数外要求语句以关键字开始 func main(){k : 3i, golang, java : 3, true, java~
}基本类型 居然没有字符 boolstring// int, uint 和 uintptr 在 32 位系统上通常为 32 位宽在 64 位系统上则为 64 位宽。
// 整形应使用 int 类型除非特需使用固定大小 or 无符号的整数类型。
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr// uint8 的别名
byte // int32 的别名, 表示一个 Unicode 码点
rune // 两种大小的 float 型
float32 float64// 两种大小的 复数
complex64 complex128// var 也可以像 import 一样分组
var (myBool bool truemyString string fwy
)默认值 // 数值默认 0
var i int
var j float32 // 布尔默认 false
var is bool// 字符串默认 空串
var name string类型转换只能显式转换 // 注意go 不支持隐式转换设计者认为这个功能的弊端比好处多。
var i, j 1, 2
var k float32 float32(i j)// 短声明
i, j : 1, 2
k : float32(i j)类型推导变量类型由右值推导 var i int 3
// 推导 j is type of int
var j i // 当右边包含未指明类型的数值常量时新变量的类型取决于常量的精度
i : 3 // int
j : 3.14 // float64
k : 3 3.14 // float64常量 const 关键字。不能用 : 声明 // 常量可以是字符串、布尔值或数值
const world 世界// 可以使用分组、可以指定类型
const (name int 20school SZU
)数值常量数值常量是高精度的 值。一个未指定类型的常量由上下文来决定其类型。 const (Big 1 100Small Big 99
)func needInt(x int) int {return x
}func needFloat(x float32) float32 {return x
}func main(){// 两个都可以跑因为常量类型未指定fmt.Println(needInt(Small))fmt.Println(needFloat(Small))fmt.Println(needFloat(Big))fmt.Println(needInt(Big)) // error: overflows int
}二. 流程控制语句 for、switch、if 和 defer 循环语句 sum : 0
/*** 1. go 只有一种循环for 循环* 2. 三个构成部分外没有小括号用 ; 隔开* 3. 大括号{ }是必须的
*/
for i : 0; i 10; i {sum i
}// 4. 初始化 后置语句可省略
for ; sum 100; {sum sum
}// 5. for 是 go 中的 while。去掉分号有
for sum 1000 {sum sum
}// 6. 条件也可省略。下例为“紧凑的无限循环”
for {
} 判断语句 // 1. 和 for 一样省略小括号必须大括号
you : true
if you {fmt.Println(you~you~you)
}// 2. 和 for 一样在条件表达式之前可以执行一个简单语句
if me : 3 * 4; me 12 {fmt.Prinln(简单语句声明的变量作用域仅在该if语句中)
}
// 当然对应的 else 块中也可以使用该变量
else {me me
}switch 语句 /*** 1. Go 自动提供了在这些语言中每个 case 后面所需的 break 语句。* 2. 除非以 fallthrough 语句结束否则分支会自动终止 (接1)* 3. case 无需为常量且取值不必为整数* 4. 同 if 可以在先执行一个简单语句
*/
func main(){switch os : macOS; os {case Linux:fmt.Println(LinuxOS)case mac:fmt.Println(macOS)default:fmt.Println(os)}// 5. switch switch true 无条件 switch 相当于 switch true
}defer 语句将函数推迟到外层函数返回之后执行。 参数会立即求值但是函数要返回之后才调用。 func main(){defer fmt.Println(hello)fmt.Print(world)// 输出world hello
}defer 栈推迟的函数调用会被压入一个栈中。当外层函数返回时被推迟的函数会按照后进先出的顺序调用。 func main(){for i : 1; i 4; i {defer fmt.Print(i)}fmt.Print(end)// 输出end 3 2 1
}三. 更多类型 struct、slice 和映射 指针
// 和 C 相同的两个运算符*、
var(a int 3// 注意定义时 * 在类型前p *int a
)
fmt.Println(*p)
// 零值为 nil
p nil结构体一个结构体struct就是一组字段field // 声明格式
type Vertex struct {x inty int
}
func main(){// 1. 大括号构造temp : Vertex{1, 2}// 2. 用.来访问成员fmt.Println(temp.x)// 3. 结构体指针p : temp// 4. 允许隐式间接引用fmt.Println((*p).x) // 这样写太啰嗦了fmt.Println(p.x)// 5. 使用 Name: 语法可以仅列出部分字段。顺序无关temp : Vertex{x: 1} // 1, 0temp : Vertex{} // 0, 0
}数组 // var 格式
var a [2]int
a[0] 3// : 格式
stinrgs : [2]string{fwy, szu}切片1动态、灵活在实践中比数组更常用 arr1 : [3]int{1, 2, 3}
// 1. [low, height) 闭开区间
// 不存储数据只是描述数组的一部分共享同一个数组
sec1 : arr1[1 : 2]// 2. 创建一个数组然后构建一个引用了它的切片此处[]内没有大小声明
sec2 : []int{1, 2, 3}// 3. 以默认忽略上下界下界为0上界为切片长度
arr2 : [3]int{1, 2, 3}
// 这四个切片实际上相同
sec3 : arr[: 3]
sec4 : arr[0 :]
sec5 : arr[:]
sec6 : arr[0 : 3]切片2 // capacity从切片第一个元素到其底层数组元素末尾的个数
// length包含的元素个数
s : []int{1, 2, 3, 4, 5} // 5, 5
fmt.Println(cap(s), len(s)) // 直接通过cap()、len() 获取// 零值 nillen 和 cap 都是0而且【没有底层数组】
var ss []int切片3make 函数分配一个元素为零值的数组并返回一个引用了它的切片 这也是分配动态数组的方式 a : make([]int, 5)
// 指定容量则加入第三个参数
b : make([]int, 5, 7)// 切片可包含任何类型包括其它的切片。
board : [][]string{[]string{-, -, -},[]string{-, -, -},
}切片4append 追加元素 // 1. 追加到末尾
// 2. 容量不够时会创造新的切片然后再返回新切片
var s []int
append(s, 0)
// 3. 可一次添加多个元素
append(s, 1, 2, 3)for 循环的 range 形式 // 1. 遍历切片时每次会返回两个值index、element的副本
var arr []int{1, 2, 3}
for i, v : range pow {fmt.Prinln(i, v)
}// 2. 可以用 _ 来忽略返回值
for i, _ : range pow
for _, v : range pow
// 3. 如果只需要索引也可以直接忽略第二个参数
for i : range pow映射1 // 1. 零值为 nil既没有键也不能添加键
// 2. make 函数会返回给定类型的映射并将其初始化备用
m : make(map[string]int)
m[fwys age] 20
// 3. 必须有键名
var mm map[string]int {fwy : 20JOJO : 200
}
// 4. 若顶级类型只是一个类型名你可以在文法的元素中省略它。
var mmm map[string]Vertex{Bell Labs: Vertex{40.68433, -74.39967,},// 省略Google: {37.42202, -122.08408,},
}映射2 // 增 or 改
m[fwy] 21
// 查
age m[fwy]
// 删
delete(m, key)
// contains通过双赋值实现
element, ok m[key]
// 存在则 ok true否则 ok false
// 不存在则 element 为类型 nil 值
// 如果 element, ok 未声明可以用短变量声明
element, ok : m[key]函数 // 函数也是值。它们可以像其它值一样传递。(有点离谱。。但是也是这么个理)
func compute(fn func(float64, float64) float64) float64{return fn(3, 4)
}
// 翻译compute函数的参数为“一个返回值为float型的需要两个float参数的函数”返回值为float类型func main(){// 这个也挺离谱的整得有点像 Java 的匿名类了 mySqrt : func(x, y float64) {return math.Sqrt(x * x, y * y)}compute(mySqrt())
}函数的闭包 // 闭包是一个函数值它引用了其函数体之外的变量。该函数可以访问并赋予其引用的变量的值
// adder() 的返回值类型 func(int) int
func adder() func(int) int {sum : 0return func(x int) int {sum xreturn sum}
}func main() {pos, neg : adder(), adder()fmt.Println(pos(1)) // 1fmt.Println(neg(-1)) // -1
}// 斐波那契闭包
func fibonacci() func() int {// 初始化这行代码只跑了一次a, b : 0, 1// func() 一直引用了函数体外的a、b并且进行了修改return func() int {temp : aa, b b, a breturn temp}func main() {fibo : fibonacci()for i : 0; i 10; i {fmt.Println(fibo())}}
}四. 方法和接口 方法 // 1. go 没有类但是可以给结构体定义“方法”
// 2. 方法: 带特殊的“接收者参数”的函数方法即函数
type Vertex struct {x inty int
}// 3. 接收者参数位于函数名前
func (v Vertex) getX() int {return v.x
}// 4. 只能为包内定义的类型的接收者声明方法包外像int 之类的内建类型也不行
// 可以通过这种方法曲线救国
type myInt int
func (v myInt) getInt() int {return (int)v
}// 5. 为指针接收者声明方法
func (v *Vertex) scale(num int) {v.x * numv.y * num
}// 如果不是指针而是值那么将会在副本上修改而不是本体对于函数的其他参数也是如此
func (v Vertex) scale(num int) {v.x * numv.y * num
}// 6. 带指针参数的函数必须接受一个指针而以指针为接收者的函数则“值和指针都可以”
// 相反值也是一样
p.Abs() // 会被解释为 *p).Abs()// 7. 使用指针为接收者好处
// 1可以修改值
// 2不用复制值造成资源浪费接口 def // 接口类型 是由一组方法签名定义的集合。
// 接口类型的变量可以保存任何实现了这些方法的值。
type Abser interface {Abs() float64
}type MyFloat float64
func (mf MyFloat) Abs() float64 {return float64(-mf);
}type Vertex struct {x, y float64
}func (v *Vertex) Abs() float64 {return x y
}func main() {var (abser Absermf math.Sqrt(30)v Vertex{3, 4})abser MyFloat(mf)abser.Abs()abser vabser.Abs()// error: abser v
}// 1. 没有 implements 关键字无需显示声明// 2. 接口也是值可以传递。
// 可以看做包含值和具体类型的元组(value, type)会保存一个具体底层类型的具体值// 3. 即便接口内的具体值为 nil方法仍然会被 nil 接收者调用。“底层值为 nil 的接口值”
// ps 保存了 nil 具体值的接口其自身并不为 nil。// 4. nil 接口值和 3 不同会产生运行时错误。“nil 接口值”
// 也就是找不到具体方法的值而 3 则是找到具体方法找不到具体对象
type MyInterface interface {M()
}
func main() {var i MyInterfacei.M()
}空接口定义了 0 个方法的接口可保存任何类型的值 // 被用来处理未知类型的值
func main() {var i interface{}fmt.Printf((%v, %T)\n, i, i)// (nil, nil)i 42fmt.Printf((%v, %T)\n, i, i)// (42, int)i hellofmt.Printf((%v, %T)\n, i, i)// (hello, string)
}**类型断言**提供了访问接口值底层具体值的方式。 // t i.(T)
func main() {var i interface{} hellos : i.(string) // hellos, ok : i.(string) // hello yes// 将会赋予对应零值f, ok : i.(float64) // 0, false// 失败且没有接收判断值的情况会报错f : i.(float64)
}类型选择 func do(i interface{}) {switch v : i.(type) {case int : fmt.Println(int)case string:fmt.Println(string) default:fmt.Println(I dont know how %T !, v)}
}func main() {do(32)do(hello)do(true)
}Stringer属于 fmt 包 type Stringer interface {// 用于描述自己类似 Java 的 toString()String() string
}错误类似5是一个内建接口 type error interface {Error() string
}// 通常函数会返回一个 error 值 error 值为 nil 时成功否则失败
type MyError struct {when time.Timewhat string
}func (myError *MyError) Error() string {return fmt.Sprintf(%v, %s, myError.when, myError.what)
}func run() error {return MyError{time.Now(),it didnt work }
}func main() {if err : run(); err ! nil {fmt.Println(err)}
}Reader io 包 func main() {// 新建一个 Readerr : strings.NewReader(Hello Golang~);// 新建一个容量为8的切片mySlice : make([]byte, 8);for {// func (T) Read(b []byte) (n int, err error)n, err : r.Read(mySlice)fmt.Printf(n %v err %s mySlice %v \n, n, err, mySlice)// 遇到数据流结尾时会返回一个 EOF 错误if err io.EOF {break;}}
}待补充图像
五. 并发 Go 程goroutine Go 运行时管理的轻量级线程。 // f, x, y 和 z 的求值发生在当前的 Go 程中而 f 的执行发生在新的 Go 程中。
// go f(x, y, z)func sum(s []int, c chan int) {sum : 0;for _, v : range s {sum v}// 把 sum 的值送入流信道中c - sum
}func main() {arr : []int{1, 2, 3, -1, -2 ,7}// 创建管道c : make(chan int)// 各负责一半go sum(arr[: len(arr)/2], c)go sum(arr[len(arr)/2 :], c)// 都结束后再从信道中获取x, y : - c, - cfmt.Println(x y)
} 带缓冲的信道 // 1. 通过在 make() 第二个参数设置缓冲
ch : make(chan int, 2)
ch - 1
ch - 2
ch - 3 // 填满后会阻塞range close // 1. 可以通过分配第二个参数来判断信道是否关闭
ch make(chan int)
// 如果已经关闭了 ok false
v, ok : -c// 2. 如果使用 range会不断从信道接收值直到他被关闭
for i : range c {
}select 语句 // 1. 使一个 Go 程可以等待多个通信操作。
// 2. 会阻塞到任一分支可行如多个可行则随机一个
func fibonacci(c, quit chan int) {x, y : 0, 1for {select {case c - x:x, y y, x y// quit 可流出时case - quit:fmt.Println(quit)returndefault:fmt.Println(其他分支都没有准备好)}}
}func main() {c : make(chan int)quit : make(chan int)// 有 Java 匿名类内味了go func() {for i : 0; i 10; i {fmt.Println(- c)}quit - 1}()fibonacci(c, quit)
}