bit clear (and not)操作,x&^y表示把y按位取反,再和x做位与&操作,也即x&(^y)
<<
按位左移
>>
按位右移
比较操作符
Operator
Description
==
等于
!=
不等于
<
小于
<=
小于等于
>
大于
>=
大于等于
逻辑操作符
Operator
Description
&&
逻辑与
||
逻辑或
!
逻辑非
其它
Operator
Description
&
取变量地址或者创建指针
*
取指针指向的变量的值
<-
管道channel的发送和接收操作符
声明
类型在标识符后面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var foo int// 只声明,不做初始化 var foo int = 42// 声明的同时做初始化 var foo, bar int = 42, 1302// 一次声明和初始化多个变量 var foo = 42// 忽略类型,编译器自行推导 foo := 42// 简写,只能在函数或者方法体内使用,没有var关键字,变量类型也是隐式推导而来 const constant = "This is a constant"
// iota的值从0开始,用于常量的数值递增 const ( _ = iota a b c = 1 << iota d ) fmt.Println(a, b) // 1 2 (0被赋值给了_,相当于被跳过了) fmt.Println(c, d) // 8 16 (2^3, 2^4)
// 在最后一个参数的类型前面加...表示函数的最后一个传参可以有0个或者多个 // 函数调用和普通函数一样,只是我们可以传递任意多个参数 funcadder(args ...int)int { total := 0 for _, v := range args { // 遍历传进来的参数, args是一个slice类型变量 total += v } return total }
// Go只有for,没有while和until关键字 for i := 1; i < 10; i++ { } for ; i < 10; { // 相当while循环的效果 } for i < 10 { // 如果只有一个条件,可以省略分号,也相当于while循环 } for { // 可以忽略条件,相当于while (true) } // 循环里可以使用break/continue来控制循环执行逻辑 // break/continue还可以和循环外的label一起使用,用于控制外层循环的执行逻辑 // continue here表示外层的for循环继续执行,继续执行时外层for循环里的i会++ // break there表示退出外层循环,也就是退出整个循环了 here: for i := 0; i < 2; i++ { for j := i + 1; j < 3; j++ { if i == 0 { continue here } fmt.Println(j) if j == 2 { break } } }
there: for i := 0; i < 2; i++ { for j := i + 1; j < 3; j++ { if j == 1 { continue } fmt.Println(j) if j == 2 { break there } } }
// 和if一样,switch的value之前可以添加一条赋值语句 switch os := runtime.GOOS; os { case"darwin": ... }
// switch的case条件还可以是比较语句 number := 42 switch { case number < 42: fmt.Println("Smaller") case number == 42: fmt.Println("Equal") case number > 42: fmt.Println("Greater") }
var a [10]int// 声明一个长度为10的int数组,数组长度也是数组类型的一部分 a[3] = 42// 设置数组元素的值 i := a[3] // 读数组元素的值
// 声明和初始化 var a = [2]int{1, 2} a := [2]int{1, 2} //简写 a := [...]int{1, 2} // 编译器自行推导数组长度
切片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
var a []int// 声明切片,和数组类型声明类似,不需要指定长度 var a = []int {1, 2, 3, 4} // 声明和初始化切片 a := []int{1, 2, 3, 4} // 简写 chars := []string{0:"a", 2:"c", 1: "b"} // ["a", "b", "c"]
var b = a[lo:hi] // 通过下标索引从已有的数组或切片创建新切片,下标前闭后开,取值从lo到hi-1 var b = a[1:4] // 取切片a的下标索引从1到3的值赋值给新切片b var b = a[:3] // :前面没有值表示起始索引是0,等同于a[0:3] var b = a[3:] // :后面没有值表示结束索引是len(a),等同于a[3:len(a)] a = append(a,17,3) // 往切片里添加新元素 c := append(a,b...) // 把切片a和b的值拼接起来,组成新切片
// 使用make来创建切片 a = make([]byte, 5, 5) // make的第2个参数是切片长度,第3个参数是切片容量 a = make([]byte, 5) // 第3个切片容量参数可选,即可以不传值
// 根据数组来创建切片 x := [3]string{"Лайка", "Белка", "Стрелка"} s := x[:] // 切片s指向了数组x的内存空间,改变切片s的值,也会影响数组x的值
// 从管道读数据,直到管道被关闭 for i := range ch { fmt.Println(i) }
// select关键字在多个管道操作上阻塞,只要有1个不阻塞了,对应case分支就会被执行 funcdoStuff(channelOut, channelIn chanint) { select { case channelOut <- 42: fmt.Println("We could write to channelOut!") case x := <- channelIn: fmt.Println("We could read from channelIn") case <-time.After(time.Second * 1): fmt.Println("timeout") } }
Channel原则
给值为nil的管道发送数据会一直阻塞
1 2 3
var c chanstring c <- "Hello, World!" // fatal error: all goroutines are asleep - deadlock!
从值为nil的管道接收数据会一直阻塞
1 2 3
var c chanstring fmt.Println(<-c) // fatal error: all goroutines are asleep - deadlock!
往被关闭的管道发送数据会panic
1 2 3 4 5
var c = make(chanstring, 1) c <- "Hello, World!" close(c) c <- "Hello, Panic!" // panic: send on closed channel
从被关闭的管道接收数据会立即返回零值
1 2 3 4 5 6 7 8
var c = make(chanint, 2) c <- 1 c <- 2 close(c) for i := 0; i < 3; i++ { fmt.Printf("%d ", <-c) } // 1 2 0
打印
1 2 3 4 5 6 7 8 9 10 11 12
fmt.Println("Hello, 你好, नमस्ते, Привет, ᎣᏏᏲ") //基本的打印,会自动换行 p := struct { X, Y int }{ 17, 2 } fmt.Println( "My point:", p, "x coord=", p.X ) // 打印结构体和字段值 s := fmt.Sprintln( "My point:", p, "x coord=", p.X ) // 打印内容到字符串变量里