该备忘单提供了帮助您使用 Golang 的基本语法和方法。
入门 hello.go 1 2 3 4 5 package mainimport "fmt" func main () { fmt.Println("Hello, world!" ) }
直接运行
1 2 $ go run hello.go Hello, world!
或者在 Go repl 中尝试一,go
命令参考
变量 1 2 3 4 5 6 7 var s1 string s1 = "Learn Go!" var b, c int = 1 , 2 var d = true _ , e = 10 , 20
简短声明
1 2 3 s1 := "Learn Go!" b, c := 1 , 2 d := true
参见:基本类型
函数 1 2 3 4 5 6 7 8 9 10 package mainimport "fmt" func main () { fmt.Println("Hello world!" ) say("Hello Go!" ) } func say (message string ) { fmt.Println("You said: " , message) }
参见:函数(Functions)
注释
if 语句 1 2 3 if true { fmt.Println("Yes!" ) }
参见:条件控制
Golang 基本类型 字符串 Strings 1 2 3 4 5 6 7 s1 := "Hello" + "World" s2 := `A "raw" string literal can include line breaks.` fmt.Println(len (s1)) fmt.Println(string (s1[0 :5 ]))
字符串的类型为 字符串
数字 Numbers 1 2 3 4 5 6 num := 3 num := 3. num := 3 + 4i num := byte ('a' ) var u uint = 7 var p float32 = 22.7
操作符 Operators 1 2 3 4 x := 5 x++ fmt.Println("x + 4 =" , x + 4 ) fmt.Println("x * 4 =" , x * 4 )
参见:更多操作符
布尔值 Booleans 1 2 isTrue := true isFalse := false
操作符 1 2 3 4 5 fmt.Println(true && true ) fmt.Println(true && false ) fmt.Println(true || true ) fmt.Println(true || false ) fmt.Println(!true )
参见:更多操作符
数组 Arrays 1 2 3 4 ┌────┬────┬────┬────┬─────┬─────┐ | 2 | 3 | 5 | 7 | 11 | 13 | └────┴────┴────┴────┴─────┴─────┘ 0 1 2 3 4 5
1 2 3 4 5 6 primes := [...]int {2 , 3 , 5 , 7 , 11 , 13 } fmt.Println(len (primes)) fmt.Println(primes) fmt.Println(primes[0 :3 ])
1 2 3 4 5 var a [2 ]string a[0 ] = "Hello" a[1 ] = "World" fmt.Println(a[0 ], a[1 ]) fmt.Println(a)
2d array 1 2 3 4 5 6 7 8 var twoDimension [2 ][3 ]int for i := 0 ; i < 2 ; i++ { for j := 0 ; j < 3 ; j++ { twoDimension[i][j] = i + j } } fmt.Println("2d: " , twoDimension)
指针(Pointers) 1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { b := *getPointer() fmt.Println("Value is" , b) } func getPointer () (myPointer *int ) { a := 234 return &a } var p *int *p = 123
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func main () { a := 10 a = 20 var p *int p = &a ptr := new (int ) }
参见:指针(Pointers)
切片(Slices) 1 2 3 4 5 6 7 8 9 10 s := make ([]string , 3 ) s[0 ] = "a" s[1 ] = "b" s = append (s, "d" ) s = append (s, "e" , "f" ) fmt.Println(s) fmt.Println(s[1 ]) fmt.Println(len (s)) fmt.Println(s[1 :3 ]) slice := []int {2 , 3 , 4 }
另见:切片示例
常量(Constants) 1 2 3 4 const s string = "constant" const Phi = 1.618 const n = 500000000 const d = 3e20 / n
常量声明可以使用 iota常量生成器 初始化,它用于 生成一组以相似规则初始化的常量,但是不用每行都 写一遍初始化表达式。 注意:
在一个const声明语句中,在第一个声明的常量所在的行,iota被置为0,然后在每一个有常量声明的行加一。
写在同一行的值是相同的
1 2 3 4 5 6 const ( a = iota b c )
类型转换 Go语言中不允许隐式转换,所有类型转换必须显式声明(强制转换),而且转换只能发生在两种相互兼容的类型之间。
1 2 3 4 5 i := 90 f := float64 (i) u := uint (i) s := string (i)
字符串与其他类型的相互转换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 str := "90" i, err := strconv.Atoi(str) if err != nil { fmt.Println("转换错误:" , err) } else { fmt.Println(i) } f, err := strconv.ParseFloat(str, 64 ) bytes := []byte (str) str = strconv.Itoa(i) str = strconv.FormatFloat(f, 'f' , 2 , 64 ) str = string (bytes[:])
Golang 字符串 字符串函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "fmt" s "strings" ) func main () { fmt.Println(s.Contains("test" , "e" )) fmt.Println(len ("hello" )) fmt.Println("hello" [1 ]) fmt.Println(string ("hello" [1 ])) }
fmt.Printf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package mainimport ( "fmt" "os" ) type point struct { x, y int } func main () { p := point{1 , 2 } fmt.Printf("%v\n" , p) fmt.Printf("%+v\n" , p) fmt.Printf("%#v\n" , p) fmt.Printf("%T\n" , p) fmt.Printf("%t\n" , true ) fmt.Printf("%d\n" , 123 ) fmt.Printf("%b\n" , 14 ) fmt.Printf("%c\n" , 33 ) fmt.Printf("%x\n" , 456 ) fmt.Printf("%f\n" , 78.9 ) fmt.Printf("%e\n" , 123400000.0 ) fmt.Printf("%E\n" , 123400000.0 ) fmt.Printf("%s\n" , "\"string\"" ) fmt.Printf("%q\n" , "\"string\"" ) fmt.Printf("%x\n" , "hex this" ) fmt.Printf("%p\n" , &p) fmt.Printf("|%6d|%6d|\n" , 12 , 345 ) fmt.Printf("|%6.2f|%6.2f|\n" , 1.2 , 3.45 ) fmt.Printf("|%-6.2f|%-6.2f|\n" , 1.2 , 3.45 ) fmt.Printf("|%6s|%6s|\n" , "foo" , "b" ) fmt.Printf("|%-6s|%-6s|\n" , "foo" , "b" ) s := fmt.Sprintf("a %s" , "string" ) fmt.Println(s) fmt.Fprintf(os.Stderr, "an %s\n" , "error" ) }
另见:fmt
函数实例
实例
Result
Contains(“test”, “es”)
true
Count(“test”, “t”)
2
HasPrefix(“test”, “te”)
true
HasSuffix(“test”, “st”)
true
Index(“test”, “e”)
1
Join([]string{“a”, “b”}, “-“)
a-b
Repeat(“a”, 5)
aaaaa
Replace(“foo”, “o”, “0”, -1)
f00
Replace(“foo”, “o”, “0”, 1)
f0o
Split(“a-b-c-d-e”, “-“)
[a b c d e]
ToLower(“TEST”)
test
ToUpper(“test”)
TEST
Golang 条件控制 有条件的 1 2 3 4 5 6 7 8 a := 10 if a > 20 { fmt.Println(">" ) } else if a < 20 { fmt.Println("<" ) } else { fmt.Println("=" ) }
if 中的语句 1 2 3 4 x := "hello go!" if count := len (x); count > 0 { fmt.Println("Yes" ) }
1 2 3 if _, err := doThing(); err != nil { fmt.Println("Uh oh" ) }
Switch 1 2 3 4 5 6 7 8 9 10 11 12 x := 42.0 switch x { case 0 : case 1 , 2 : fmt.Println("Multiple matches" ) case 42 : fmt.Println("reached" ) case 43 : fmt.Println("Unreached" ) default : fmt.Println("Optional" ) }
参见:Switch
For loop 1 2 3 for i := 0 ; i <= 10 ; i++ { fmt.Println("i: " , i) }
对于 Range 循环 1 2 3 4 5 6 nums := []int {2 , 3 , 4 } sum := 0 for _, num := range nums { sum += num } fmt.Println("sum:" , sum)
For 循环 1 2 3 4 5 i := 1 for i <= 3 { fmt.Println(i) i++ }
Continue 关键字 1 2 3 4 5 6 for i := 0 ; i <= 5 ; i++ { if i % 2 == 0 { continue } fmt.Println(i) }
Break 关键字 1 2 3 4 for { fmt.Println("loop" ) break }
Golang 结构和Maps 定义 1 2 3 4 5 6 7 8 9 10 11 12 13 package mainimport ( "fmt" ) type Vertex struct { X int Y int } func main () { v := Vertex{1 , 2 } v.X = 4 fmt.Println(v.X, v.Y) }
参见:结构(Structs)
字面量 1 2 3 4 5 v := Vertex{X: 1 , Y: 2 } v := Vertex{1 , 2 } v := Vertex{X: 1 }
您还可以输入字段名
Maps 1 2 3 4 5 6 7 8 9 10 11 12 13 m := make (map [string ]int ) m["k1" ] = 7 m["k2" ] = 13 fmt.Println(m) v1 := m["k1" ] fmt.Println(v1) fmt.Println(len (m)) delete (m, "k2" )fmt.Println(m) _, prs := m["k2" ] fmt.Println(prs) n := map [string ]int {"foo" : 1 , "bar" : 2 } fmt.Println(n)
指向结构的指针 1 2 v := &Vertex{1 , 2 } v.X = 2
Doing v.X
is the same as doing (*v).X
, when v
is a pointer.
Golang 函数 多个参数 1 2 3 4 5 6 7 8 func plus (a int , b int ) int { return a + b } func plusPlus (a, b, c int ) int { return a + b + c } fmt.Println(plus(1 , 2 )) fmt.Println(plusPlus(1 , 2 , 3 ))
多返回值 1 2 3 4 5 6 func vals () (int , int ) { return 3 , 7 } a, b := vals() fmt.Println(a) fmt.Println(b)
匿名函数 1 2 3 4 5 6 r1, r2 := func () (string , string ) { x := []string {"hello" , "world" } return x[0 ], x[1 ] }() fmt.Println(r1, r2)
命名返回值 1 2 3 4 5 6 7 8 func split (sum int ) (x, y int ) { x = sum * 4 / 9 y = sum - x return } x, y := split(17 ) fmt.Println(x) fmt.Println(y)
可变参数函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 func sum (nums ...int ) { fmt.Print(nums, " " ) total := 0 for _, num := range nums { total += num } fmt.Println(total) } sum(1 , 2 ) sum(1 , 2 , 3 ) nums := []int {1 , 2 , 3 , 4 } sum(nums...)
初始化函数 1 import --> const --> var --> init()
1 2 3 4 5 6 7 8 9 10 var num = setNumber()func setNumber () int { return 42 } func init () { num = 0 } func main () { fmt.Println(num) }
作为值的函数 1 2 3 4 5 6 7 8 func main () { add := func (a, b int ) int { return a + b } fmt.Println(add(3 , 4 )) }
闭包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func outer () (func () int , int ) { outer_var := 2 inner := func () int { outer_var += 99 return outer_var } inner() return inner, outer_var } inner, val := outer() fmt.Println(val) fmt.Println(inner())
关闭 1 1 2 3 4 5 6 7 func scope () func () int { outer_var := 2 foo := func () int {return outer_var} return foo } fmt.Println(scope()())
Golang 包(Packages) 导入 1 2 import "fmt" import "math/rand"
等同于 1 2 3 4 import ( "fmt" "math/rand" )
另见:导入
别名
1 2 3 4 import ( "fmt" r "math/rand" )
Packages 1 2 3 4 package mainpackage internal
另见:内部包
导出名称
另见:导出的名称
Golang 并发 协程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport ( "fmt" "time" ) func f (from string ) { for i := 0 ; i < 3 ; i++ { fmt.Println(from, ":" , i) } } func main () { f("direct" ) go f("goroutine" ) go func (msg string ) { fmt.Println(msg) }("going" ) time.Sleep(time.Second) fmt.Println("done" ) }
参见:Goroutines , Channels
WaitGroup 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport ( "fmt" "sync" "time" ) func w (id int , wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("%d starting\n" , id) time.Sleep(time.Second) fmt.Printf("%d done\n" , id) } func main () { var wg sync.WaitGroup for i := 1 ; i <= 5 ; i++ { wg.Add(1 ) go w(i, &wg) } wg.Wait() }
参见:WaitGroup
Closing channels 1 2 3 4 ch <- 1 ch <- 2 ch <- 3 close (ch)
1 2 3 4 for i := range ch { ··· }
参见:范围和关闭
缓冲通道 1 2 3 4 5 6 ch := make (chan int , 2 ) ch <- 1 ch <- 2 ch <- 3
参见:缓冲通道
Golang 错误控制 延迟函数 1 2 3 4 5 6 func main () { defer func () { fmt.Println("Done" ) }() fmt.Println("Working..." ) }
Lambda defer 1 2 3 4 5 6 7 8 func main () { var d = int64 (0 ) defer func (d *int64 ) { fmt.Printf("& %v Unix Sec\n" , *d) }(&d) fmt.Print("Done " ) d = time.Now().Unix() }
defer
函数使用当前值d
,除非我们使用指针在 main
末尾获取最终值
Defer 1 2 3 4 func main () { defer fmt.Println("Done" ) fmt.Println("Working..." ) }
参见:Defer, panic and recover
Golang 方法(Methods) 接收器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) { 函数体 } type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { return math.Sqrt(v.X * v.X + v.Y * v.Y) } func (v Vertex) valuechange() float64 { v.X += 1 return v.X } func (v *Vertex) pointerchange() float64 { v.X += 1 return v.X } func main () { v := Vertex{1 , 2 } v.Abs() v = Vertex{1 , 2 } fmt.Println(v.valuechange()) fmt.Println(v) v = Vertex{1 , 2 } fmt.Println(v.pointerchange()) fmt.Println(v) }
参见:Methods ,指针接收器
方法表达式 方法表达式相当于提供一种语法将类型方法调用显式地转换为函数调用,接收者(receiver)必须显式地传递进去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func (t T) Get(){ return t.a } func (t *T) Set(i int ){ t.a = i } type Data struct {}func (Data) TestValue () {}func (*Data) TestPointer () {} var a Data= struct {}{}Data.TestValue(a) (*Data).TestPointer (&a) y : = (&a).TestValue g : = a.TestPointer
组合结构的方法集 内嵌字段的访问不需要使用全路径,只要保证命名是唯一的就可以,尽量避免同名。如果外层字段和内层字段有相同的方法,则使用简化模式访问外层方法会覆盖内层的方法。
1 2 3 4 5 6 7 8 9 x : = X{a: 1 } y : = Y{ X : x , b : 2 , } z : = z { Y : y , c : 3 , }
组合结构的方法集有如下规则:
若类型 T 包含匿名字段 S ,则 T 的方法集包含S的方法集
若类型 T 包含匿名字段 S ,则 T 的方法集包含 S 和 S方法集
不管类型 T 中嵌入的匿名字段是 S 还是 S , T 方法集总是包含 S 和 *S 方法集
Golang 接口(Interfaces) 基本接口(Interfaces) 1 2 3 4 type Shape interface { Area() float64 Perimeter() float64 }
结构(Struct) 1 2 3 type Rectangle struct { Length, Width float64 }
结构 Rectangle
通过实现其所有方法隐式实现接口 Shape
方法(Methods) 1 2 3 4 5 6 func (r Rectangle) Area() float64 { return r.Length * r.Width } func (r Rectangle) Perimeter() float64 { return 2 * (r.Length + r.Width) }
在 Shape
中定义的方法在Rectangle
中实现
接口实例 1 2 3 4 func main () { var r Shape = Rectangle{Length: 3 , Width: 4 } fmt.Printf("Type of r: %T, Area: %v, Perimeter: %v." , r, r.Area(), r.Perimeter()) }
Golang Embed (Go version >= 1.16) 嵌入为string 1 2 3 4 5 6 7 8 9 10 11 12 13 package mainimport ( _ "embed" "fmt" ) var version string func main () { fmt.Printf("version %q\n" , version) }
嵌入为[]byte 1 2 3 4 5 6 7 8 9 10 11 12 package mainimport ( _ "embed" "fmt" ) var versionByte []byte func main () { fmt.Printf("version %q\n" , string (versionByte)) }
嵌入为embed.FS 1 2 3 4 5 6 var f embed.FSfunc main () { data, _ := f.ReadFile("hello.txt" ) fmt.Println(string (data)) }
嵌入多个文件 1 2 3 4 5 6 7 8 9 var f embed.FSfunc main () { data, _ := f.ReadFile("hello.txt" ) fmt.Println(string (data)) data, _ = f.ReadFile("hello2.txt" ) fmt.Println(string (data)) }
嵌入子文件夹下的文件 1 2 3 4 5 6 7 8 var f embed.FSfunc main () { data, _ := f.ReadFile("p/hello.txt" ) fmt.Println(string (data)) data, _ = f.ReadFile("p/hello2.txt" ) fmt.Println(string (data)) }
同一个文件嵌入为多个变量 1 2 3 4 5 6 7 8 var s string var s2 string func main () { fmt.Println(s) fmt.Println(s2) }
匹配模式 1 2 3 4 5 6 7 8 var f embed.FSfunc main () { data, _ := f.ReadFile("p/.hello.txt" ) fmt.Println(string (data)) data, _ = f.ReadFile("p/q/.hi.txt" ) fmt.Println(string (data)) }
Golang 泛型 (Go version >= 1.18) 泛型类型 1 2 3 4 type S[T int|float32|float64 ] []T ┬ ────────┬──────── ┆ ╰─── 2. 类型约束 ╰────────────── 1. 类型形参
可以使用类型实参 int 或 string 实例化
1 2 3 4 5 6 type MyMap[K int |string , V float32 | float64 ] map [K]Vvar a MyMap[string , float64 ] = map [string ]float64 { "jack_score" : 9.6 , "bob_score" : 8.4 , }
泛型函数 任意类型
1 2 3 func Add [T any ](a,b T) T { return a+b }
对类型进行约束
1 2 3 func Add [T string | int | int8 ](a,b T) T { return a+b }
类型嵌套
1 2 3 4 5 6 7 type WowStruct[T int | float32 , S []T] struct { Data S MaxValue T MinValue T } var ws WowStruct[int , []int ]
泛型函数中进行类型声明 (go version >= 1.20)
1 2 3 4 func F [T1 any ]() { type x struct {} type y = x }
泛型约束 通过接口实现
1 2 3 4 5 6 7 type Addable interface { type int , int8 , int16 , int32 , int64 , uint , uint8 , uint16 , uint32 , uint64 , uintptr , float32 , float64 , complex64 , complex128 , string } func Add [T Addable ](a,b T) T { return a+b }
使用 ~ 符号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 type Int interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 } type Uint interface { ~uint | ~uint8 | ~uint16 | ~uint32 } type Float interface { ~float32 | ~float64 } type Slice[T Int | Uint | Float] []T var s Slice[int ] type MyInt int var s2 Slice[MyInt] type MyMyInt MyIntvar s3 Slice[MyMyInt] type MyFloat32 float32 var s4 Slice[MyFloat32]
使用 ~ 时的限制:
~后面的类型不能为接口
~后面的类型必须为基本类型
泛型 Receiver 定义普通类型支持泛型
1 2 3 4 5 6 7 8 9 type MySlice[T int | float32 ] []Tfunc (s MySlice[T]) Sum() T { var sum T for _, value := range s { sum += value } return sum }
结构体支持泛型
1 2 3 4 5 6 7 type A[T int | float32 | float64 ] struct {} func (receiver A[T]) Add(a T, b T) T { return a + b }
泛型接口 1 2 3 4 5 6 7 8 9 10 type Uint interface { ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 } type ReadWriter interface { ~string | ~[]rune Read(p []byte ) (n int , err error ) Write(p []byte ) (n int , err error ) }
一般接口类型不能用来定义变量,只能用于泛型的类型约束中
杂项 关键字(Keywords)
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
运算符和标点符号
+
&
+=
&=
&&
==
!=
(
)
-
|
-=
|=
||
<
<=
[
]
*
^
*=
^=
<-
>
>=
{
}
/
<<
/=
<<=
++
=
:=
,
;
%
>>
%=
>>=
--
!
...
.
:
&^
&^=
Go 命令 Go 编译器命令
:-
–
go command [参数]
go 命令 [参数]
go build
编译包和依赖包
go clean
移除对象和缓存文件
go doc
显示包的文档
go env
打印go的环境变量信息
go bug
报告bug
go fix
更新包使用新的api
go fmt
格式规范化代码
go generate
通过处理资源生成go文件
go get
下载并安装包及其依赖
go install
编译和安装包及其依赖
go list
列出所有包
go run
编译和运行go程序
go test
测试
go tool
运行给定的go工具
go version
显示go当前版本
go vet
发现代码中可能的错误
ENV
Module
:-
–
go mod init
初始化当前文件夹,创建go.mod文件
go mod download
下载依赖的module到本地
go mod tidy
增加缺少的module,删除无用的module
go mod vendor
将依赖复制到vendor下
文件 go.mod
依赖列表和版本约束
文件 go.sum
记录 module
文件 hash
值,用于安全校验
另见