网站首页 文章专栏 Go 语言基本语法
[TOC]
使用 var 定义变量, 变量类型
// 一般形式
// var 变量名 变量类型
// 注意不需要分号
// 正确的使用方式1
var v1 int = 10
// 正确的使用方式2,编译器可以自动推导出v2的类型
var v2 = 10
// 正确的使用方式3,编译器可以自动推导出v3的类型
v3 := 10
bool
int8 byte int16 int uint uintptr
var v1 int
float32 float64
complex64 complex128
string
var v2 string
rune
pointer
var v6 *int
array
var v3 [10]int
slice
// 数组切片var
// 切片并不存储任何数据,它只是描述了底层数组中的一段。
// 切片支持默认,与 python 相同
// 切片是左闭右开
var v4 []int = v3[1:3]
append 用于给切片添加元素
var s []int
s = append(s, 0)
计算长度
// 计算现有长度
len(x)
// capacity
cap(x)
map
// map,key为string类型,value为int类型
var v7 map[string]int
// 通过双赋值检测某个键是否存在:
elem, ok = m[key]
// 遍历字典
for k, v := range scene {
fmt.Println(k, v)
}
func test(c chan int) {
c <- 1
}
c := make(chan int)
go test(c)
go test(c)
x, y := <-c, <-c // 从 c 中接收
// 信道可以带缓冲
ch := make(chan int, 2)
// 发送者可以用 close 关闭信道
// 关闭后 ok 将为 false
close(c)
v, ok := <-ch
// 可以使用 range 从信道读取数据
for i := range c {
}
// select 可以阻塞到某个分支可以继续执行为止
// 可以写入也可以读出
// 同时准备好时随机选取一个
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
default:
fmt.Println("Default option")
time.Sleep(50 * time.Millisecond)
}
要点:
- 信道必须使用 make 创建
- 信道必须先在接收端就绪,然后才能写入,也就是说必须使用 go 程才能完成信道的示例
struct
v5 struct {
f int
}
type Vertex struct {
X int
Y int
}
// 结构体
var (
v1 = Vertex{1, 2} // 创建一个 Vertex 类型的结构体
v2 = Vertex{X: 1} // Y:0 被隐式地赋予
v3 = Vertex{} // X:0 Y:0
p = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
)
// 结构体初始化
var i interface{} = "hello"
// 如果没有ok,且类型不对,会引发panic
f, ok := i.(float64)
fmt.Println(f, ok)
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
Error
是一个内建的接口
type error interface {
Error() string
}
一个错误处理的例子
i, err := strconv.Atoi("42")
if err != nil {
fmt.Printf("couldn't convert number: %v\n", err)
return
}
Error 接口无限循环实例
例子见 https://tour.go-zh.org/methods/20
分析过程参考 https://www.jianshu.com/p/c77730e03393
type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
// 这里如果只用 fmt.Sprintf(e) 会让代码陷入死循环
return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}
因为e
变量是一个通过实现Error()
的接口函数成为了error
类型,那么在 fmt.Sprint(e)
时就会调用e.Error()
来输出错误的字符串信息,于是函数相当于
func (e ErrNegativeSqrt) Error() string {
return fmt.Sprint(e.Error())
}
var s []int
s == nil
使用const
关键字
const Pi float64 = 3.14159265358979323846
与 &&
或 ||
if a < 5 {
return 0
} else {
return 1
}
要点:
否则会编译失败:
switch i {
case 0:
fmt.Printf("0")
case 1:
fmt.Printf("1")
case 2:
fallthrough
case 3:
fmt.Printf("3")
case 4, 5, 6:
fmt.Printf("4, 5, 6")
default:
fmt.Printf("Default")
}
要点:
if…else…的逻辑作用等同。
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
要点:
是,Go 语言不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多
个变量。
break,可以选择中断哪一个循环
package mymath
import "errors"
func Add(a int, b int) (ret int, err error) {
if a < 0 || b < 0 { // 假设这个函数只支持两个非负数字的加法
err= errors.New("Should be non-negative numbers!")
return
}
return a + b, nil // 支持多重返回值
}
要点:
将函数作为参数时,可以用 func()
,下面是一个例子
// 注册一个回掉函数
// 注意返回值类型要相同
func registerFunc(myFunc func() error){
}
延迟语句的执行,到 return 之前都不会执行。
package main
import "fmt"
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
}
推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
每次遍历时会返回一个index
和value
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
delete(m, key)
闭包的关键在于参数在生成闭包时确定,返回值在调用时确定。
package main
import "fmt"
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 < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
func (T) Read(b []byte) (n int, err error)
Reader
用数据填充给定的字节切片并返回填充的字节数和错误值。在遇到数据流的结尾时,它会返回一个 io.EOF 错误。示例代码创建了一个 strings.Reader
并以每次 8 字节的速度读取它的输出。
r := strings.NewReader("Hello, Reader!")
b := make([]byte, 8)
for {
n, err := r.Read(b)
if err == io.EOF {
break
}
}
自己实现 reader
方法时,注意在函数内对切片赋值,返回字节数和错误值。
func (r MyReader) Read(b []byte) (int, error) {
b[0] = byte('A')
return 1, nil
}
Reader
数据流处理,见 https://tour.go-zh.org/methods/23
// 该例子中,使用 rot13Reader 并在其中使用了 r 来顺序处理数据流
type rot13Reader struct {
r io.Reader
}
func (this *rot13Reader) Read(b []byte) (int, error) {
n, e := this.r.Read(b)
for i := 0; i < n; i++ {
b[i] = rot13(b[i])
}
return n, e
}
go f(x, y, z)
mux sync.Mutex
mux.Lock()
// Lock 之后同一时刻只有一个 goroutine 能访问
// some options
mux.Unlock()