本文将介绍 Go 语言的基础语法,包括环境配置、数据类型、流程控制、函数、结构体、接口、异常、文本处理、并发编程、网络编程等。本文是对多个 Go 入门视频的总结,并结合个人理解对内容进行了简化。由于水平有限,文中可能存在些许错误,烦请评判指正。
前言
Go 的作者:Rob Pike(罗伯·派克)、Ken Thompson(肯·汤姆森)、Robert Griesemer(罗伯特·格里茨默)。
Go 的开源时间:2009 年 11 月 10 日。
Rob Pike 曾说:“你是否认同 Go,取决于你是否认同少就是多,还是少就是少(Less is more or less is less)”。Go 的设计哲学是:将简单、使用体现得淋漓尽致。
使用 Go 的项目:Docker、Kubernetes、etcd、beego、codis。
使用 Go 的公司:Google、Faebook、腾讯、百度、七牛云、京东、小米、字节跳动。
环境配置
下载地址:All releases - The Go Programming Language (google.cn),推荐下载 zip 格式。
配置环境变量:添加以下变量,并将 %GOROOT%\bin
添加到 Path
变量中。
变量 | 值 | 说明 |
---|---|---|
GOROOT | D:\Development\Environment\Go\Go-1.23.1 | Go 安装目录 |
GOPATH | D:\LocalRepository\Go | Go 依赖安装目录 |
GOPROXY | https://mirrors.aliyun.com/goproxy/ | Go 依赖镜像 |
CMD 执行 go version
查看 Go 版本。
集成开发环境:GoLand by JetBrains: More than just a Go IDE
基础语法
注释
// 单行注释(推荐)
/*
多行注释
*/
包
package main
// 普通
import "fmt"
// 忽略
import _ "fmt"
// “解构”
import . "fmt"
// 别名
import ifmp "fmt"
// “分组”
import (
"fmt"
"os"
)
// 主函数
func main(){
}
一个可执行程序必须包含一个 main 包,一个 main 包必须包含一个 main 函数。
所在目录(父级)相同 go 文件的包名必须相同。
变量
变量被声明后必须被使用。
// 定义
var a int
var a, b string
var (
a string
b string
)
// 定义并初始化
var a string = "a"
var a, b string = "a", "b"
var a, b = "a", "b"
a, b := "a", "b" // 自动类型推导
零值(默认值):整型为0,浮点型为0.0,字符串为空字符串,布尔型为false,切片、函数、指针默认为 nil。
变量遵循驼峰命名。对于全局变量,若首字母大写,则认定为 “public”。
交换变量的值。
a, b, c = b, c, a
匿名变量。匿名变量不占用空间,不会分配内存。
a, _ := getTwo()
_ = getOne()
变量作用域:局部变量、全局变量。全局变量与局部变量可同名。
// 全局变量
age := 14
func main(){
// 局部变量
age := 15
fmt.Println(age) // 15
}
常量。常量的定义和初始化与变量类似。
// 单个常量
const a = 1
// 多个常量
const a, b = 1, 2
const (
b = 2
c = 3
)
// iota
const (
a = iota // 0
b // 1
c = "c" // c
d // c
e = 100 // 100
f // 100
g = iota // 6
h // 7
)
const (
i = iota //0
j // 1
)
数据类型
布尔型:默认 false。
var flag = true
整型。字符用 int32 存储。
类型 | 描述 |
---|---|
uint8 / byte | 0 到 2^8 |
uint16 | 0 到 2^16 |
uint32 / uint(32位系统) | 0 到 2^32 |
uint64 / uint(64位系统) | 0 到 2^64 |
int8 | -2^7 到 2^7-1 |
int16 | -2^15 到 2^15-1 |
int32 / rune / int(32位系统) | -2^31 到 2^31-1 |
int64 / int(64位系统) | -2^63 到 2^64-1 |
浮点型。
类型 | 描述 |
---|---|
float32 | IEEE-754 32 位浮点数 |
float64 | IEEE-754 64 位浮点数 |
字符串。
var s string = "tom"
fmt.Println(s[0])
类型转换。
// 数值转数值
b := float64(a)
// 转字符串
s := strconv.FormatInt(int64(v), 10)
s := strconv.Itoa(v) // 特殊
// 字符串转数值
v, _ := strconv.ParseInt(s, 10)
v, _ := strconv.Atoi(s) // 特殊
指针:无需手动回收,内存回收由 GC 自动完成。
var p *int // 默认nil
var p = &a
var p = new(int)
var b = *p
数组:数组大小必须为常量。
var arr [5]int
var arr [5]int = [5]int{1, 2} // 未初始化的值默认为0
var arr = [5]int{1, 2, 3, 4}
arr := [5]int{1, 2, 3, 4}
a := [3]int{1, 2, 3}
b := [3]int{1, 2, 3}
fmt.Println(a == b) // true
切片:自动扩容。
var a []int
var a []int = []int{1, 2, 3}
var a = []int{1, 2, 3}
a := []int{1, 2, 3}
a := make([]int, 10, 15) // 类型 长度 容量
// 长度
len(a)
// 容量
cap(a)
// 追加
a = append(a, 1)
a = append(a, b...)
// 截取
b := a[1:2:1] // [low:high:max] 左边右开 长度=high-low 容量=max-high
b := a[1:2]
b := a[:2]
b := a[1:]
// 数组切片-浅拷贝
a := []int{1, 2, 3}
b := a[1:2]
b = append(b, 4)
b[0] = 5
fmt.Println(a) // 1 5 4
fmt.Println(b) // 5 4
map。
var mp map[string]int
var mp = map[string]int{"a": 1, "b": 2}
mp := make(map[string]int, 10)
运算符
算术运算符
+ - * / % ++ --
关系运算符
== != > >= < <=
逻辑运算符
&& || !
位运算符:a &^ b,将 a 中与 b 中 1 的对应位置 0,称为位清空。
& | ^ &^ << >>
赋值运算符
= += -= *= /= %= <<= >>= &= ^= |=
输入输出
fmt.Println(1)
fmt.Printf("%d", 2)
fmt.Print(3)
fmt.Scan(&age)
fmt.Scanln(&age)
fmt.Scanf("%s", &age)
流程控制
if-else
if age < 18 {
} else if age < 35 {
} else {
}
// 含初始化语句
if a := 10; a >= 10 {
} else if b := 20; b >= 20 {
}else {}
switch:fallthrough、break。
// 执行匹配项
switch age {
case 18:{}
case 35, 45:{}
default:{}
}
// 执行最后一个匹配项
switch {
case age < 18:{}
case age < 35:{}
default:{}
}
// 执行true
switch {
case true:{}
case false:{}
default:{}
}
// fallthrough执行下一个case
// break跳出switch
switch idx {
case 1:
fallthrough
case 2:
break
fallthrough
default:
}
// 判断类型
switch x.(type) {
case string:
case int:
default:
}
for:break、continue。
for i := 0; i < 10; i++ {}
i := 0
for ; i < 10; i++ {}
i := 0
for i < 10 { i++ }
for { }
for i := range s {}
for i, ch := range s { }
goto
func f() {
goto L1
fmt.Println(1)
L1:
fmt.Println(2)
}
函数
func say(a, b string) (c, d string) {
return b, a
}
func main() {
e, f := say("a", "b")
}
// 可变参数
func say(cnt int, args ...string) {
fmt.Println(cnt)
for _, v := range args {
fmt.Println(v)
}
}
// 匿名函数(立即执行)
func main() {
func() {
fmt.Println("s")
}()
}
参数传递
- 值传递:int、float64、string、bool、array等。
- 引用传递:slice、map、chan等。
// 执行顺序:d、e、c、b、a,defer逆序执行
func main() {
defer a()
defer b()
defer c()
d()
e()
}
// 函数类型
var f func(int,int)
var f = func(int, int) { }
// 回调函数
func f1(a, b int) int {
return a + b
}
func f2(a, b int, f func(int, int) int) int {
return f(a, b)
}
// 闭包
func main() {
fc := f()
fmt.Println(fc()) // 1
fmt.Println(fc()) // 2
}
func f() func() int {
i := 0
return func() int {
i++
return i
}
}
main 函数:一个可执行程序必须包含一个 main 包,一个 main 包必须包含一个 main 函数,仅 main 包下的 main 可作为入口函数。
package main
func main() {
}
init 函数:在导入一个包的同时,会直接执行这个包的 init(),main 包的 init() 会先于 main() 执行。
内置函数。
len()
cap()
a = append(a, 1)
a = append(a, b...)
a := []int{1, 2, 3}
b := []int{4, 5}
copy(a, b)
fmt.Println(a) // 4 5 3
fmt.Println(b) // 4 5
delete(a, 1)
编码规范
导包。
import (
"fmt"
"json"
)
命名:一个目录一个 go 文件,go 文件包名与目录名保持一致,包名与目录名采用小写,多个单词用下划线分隔。
结构体
type Student struct {
id int
name string
}
func main() {
// 按顺序赋值
var s1 = Student{1, "tom"}
// 指定字段赋值
var s2 = Student{
id: 1,
name: "tom",
}
// 指针
s3 := &s1
s4 := new(Student)
fmt.Println(s1.id, s2.name)
}
type Student struct {
id int
// 首字母大写才可跨包可见(public)
Name string
}
继承
// 结构体匿名变量
type Person struct {
id int
}
type Student struct {
Person
name string
}
func main() {
s := Student{Person{1}, "tom"}
s.Person= Person{2}
s.Person.id = 1
s.id = 2
s.name = "jack"
}
// 结构体指针匿名变量
type Person struct {
id int
}
type Student struct {
*Person
name string
}
func main() {
s := Student{&Person{1}, "tom"}
}
// 同名变量
type Person struct {
id int
}
type Student struct {
*Person
id int
}
func main() {
s := Student{&Person{1}, 2}
fmt.Println(s.id) // 2
}
// 非结构体类型匿名变量
type Student struct {
int
}
func main() {
s := Student{1}
fmt.Println(s.int)
}
方法
type Student struct {
id int
}
// 方法挂载到自定义类型
func (s Student) say() {
// s是实参的拷贝
fmt.Println(s.id)
}
func main() {
Student{1}.say()
}
type str string
// 方法挂载到自定义类型
func (s str) say() {
fmt.Println(s)
}
func main() {
s := str("hi")
s.say()
}
方法集:指针变量和非指针变量可看作共用方法集(语法糖)
type Student struct {
age int
}
func (s *Student) add(v int) {
s.age += v
}
func main() {
s := Student{1}
s.add(1)
fmt.Println(s.age) // 2
}
方法的继承。
type Person struct {
id int
}
type Student struct {
Person
}
func (p *Person) say() {
fmt.Println(p.id)
}
func main() {
s := Student{Person{1}}
s.say()
}
方法的重写。
type Person struct {
id int
}
type Student struct {
Person
}
func (p *Person) say() {
fmt.Println("p")
}
func (s *Student) say() {
fmt.Println("s")
}
func main() {
s := Student{Person{1}}
s.say() // s
s.Person.say() // p
}
方法值。
p := Person{1}
pf := p.say
pf()
方法表达式。
p := Person{1}
pf := (*Person).say
pf(&p)
接口
若一个类型实现了一个接口的所有方法,便认为该类型体实现了该接口。
type Person interface {
say()
}
type Student struct {
}
func (s *Student) say() {
fmt.Println("Student")
}
func main() {
var p Person = new(Student)
// 多态
p.say()
}
接口的继承
type Person interface {
say()
}
type GoodPerson interface {
Person
}
type Person interface {
say()
}
type GoodPerson interface {
Person
sayGood()
}
type Student struct {}
func (s *Student) say() {}
func (s *Student) sayGood() {}
func main() {
var p Person = &Student{}
var gp GoodPerson = &Student{}
// 下转上
p = gp
// 上转下 不允许
// gp = p
空接口
可以将任何类型的值赋给空类型的变量。
var v interface{}
v = &Student{}
类型断言。
// 断言v是Person类型
// ok=true表示断言成功,否则断言失败
// 若断言成功,则会将v转为Person类型并赋给sv,否则sv为零值
if sv, ok := v.(Person); ok {
sv.say()
}
func main() {
var v interface{}
v = &Student{} // Student实现了Person
switch v.(type) {
case int:
fmt.Println("int")
case Student:
fmt.Println("Student")
case Person:
fmt.Println("Person")
default:
fmt.Println("default")
}
}
// 输出Person
异常
内置 error 接口。
// builtin.go
type error interface {
Error() string
}
error 接口的实现。
// errors.go
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
使用。
func main() {
err := fmt.Errorf("%s", "error msg")
fmt.Println(err)
}
func main() {
err:=errors.New("error msg")
fmt.Println(err)
}
func div(a, b int) (res int, err error) {
if b == 0 {
err = errors.New("divide by zero")
} else {
res = a / b
}
return
}
func main() {
res, err := div(10, 0)
fmt.Println(res, err)
}
当发生致命错误时,可调用 panic 函数中断程序。
func div(a, b int) (res int, err error) {
if b == 0 {
panic("divide by zero")
}
res = a / b
return
}
recover 函数可拦截异常。
func div(a, b int) (res int, err error) {
defer func() {
if e := recover(); e != nil {
fmt.Println(e)
}
}()
if b == 0 {
panic(errors.New("divide by zero"))
}
res = a / b
return
}
文本处理
字符串操作。
strings.Contains()
strings.Join()
strings.Index()
strings.Repeat()
strings.Replace()
strings.Split()
strings.Trim()
strings.Fields()
字符串转换。
// 其他类型转string
strconv.FormatXXX()
// string转其他类型
strconv.ParseXXX()
正则表达式。
func main() {
r, s := ".*", "abc"
reg := regexp.MustCompile(r)
reg.Match([]byte(s))
reg.FindStringIndex(s)
}
JSON。
type Student struct {
Id int `json:"id"`
Name string `json:"-"`
Flag bool `json:"flag,string"`
}
func main() {
s := Student{1, "tom", true}
js, _ := json.Marshal(s)
_ = json.Unmarshal(js, &s)
}
文件操作
创建/打开文件
func Create(name string) (*File, error)
func Open(name string) (*File, error)
func OpenFile(name string, flag int, perm FileMode) (*File, error)
写文件
func WriteFile(name string, data []byte, perm FileMode) error
读文件
func ReadFile(name string) ([]byte, error)
删除文件
func Remove(name string) error
func RemoveAll(path string) error
命令行参数
os.Args
并发编程
协程
func main() {
go func() {
}()
}
// 设置CPU核数
runtime.GOMAXPROCS(1)
// 当前协程让出时间片
runtime.Gosched()
// 退出当前协程
runtime.Goexit()
channel
goroutine奉行通过通信来共享内存,而不是通过共享内存来通信。
// 通道-无缓冲
var ch = make(chan int)
func main() {
go func() {
// 存放数据,阻塞等待
ch <- 1
}()
// 阻塞等待,获取数据
d := <-ch
fmt.Println(d)
}
// 通道-有缓冲
var ch = make(chan int, 2)
func main() {
cnt := 3
go func() {
for i := 0; i < cnt; i++ {
// 存放数据,缓存区满时阻塞等待
ch <- 1
}
}()
for i := 0; i < cnt; i++ {
// 阻塞等待数据
d := <-ch
fmt.Println(d)
}
}
// 关闭通道
func main() {
ch := make(chan int, 2)
go func() {
for i := 0; i < 3; i++ {
ch <- 1
}
close(ch)
}()
for {
if v, ok := <-ch; ok {
fmt.Println(v)
} else {
break
}
}
}
func main() {
ch := make(chan int, 2)
go func() {
for i := 0; i < 3; i++ {
ch <- 1
}
close(ch)
}()
for d := range ch {
fmt.Println(d)
}
}
// 双向 单向
func main() {
// 双向
ch := make(chan int, 2)
// 单向只读
var rch <-chan int = ch
// 单向只写
var wch chan<- int = ch
}
// 通道参数
func main() {
ch := make(chan int, 2)
go read(ch)
go write(ch)
}
func read(rch <-chan int) {}
func write(wch chan<- int) {}
定时器
// 等待5s
timer := time.NewTimer(5 * time.Second)
<-timer.C
// 等待1s
time.Sleep(1 * time.Second)
// 等待5s
time.After(5 * time.Second)
timer :=time.NewTimer(time.Second)
// 重设定时器
timer.Reset(time.Minute)
// 停止定时器
timer.Stop()
// 定时执行
ticker := time.NewTicker(2 * time.Second)
for i := 0; ; i++ {
<-ticker.C
fmt.Println(time.Now().Unix())
if i >= 10 {
ticker.Stop()
break
}
}
// select
func main() {
c1, c2 := make(chan int), make(chan int)
go func() {
x, y := 1, 2
for i := 0; i < 10; i++ {
select {
// 写数据
case c1 <- x:
fmt.Println("c1", i, x)
x, y = y, x
// 读数据
case k := <-c2:
fmt.Println("c2", i, k)
}
}
// 对于每轮循环,select会随机选择一个未阻塞的case来执行
// 如果所有case都阻塞,select会阻塞
}()
for i := 0; i < 3; i++ {
// 读数据
<-c1
// 写数据
c2 <- i
}
}
// 超时取消
go func() {
label:
for {
select {
case v := <-ch:
fmt.Println(v)
case <-time.After(time.Second * 5):
fmt.Println("timeout")
break label
}
}
}()
网络编程
Scoket编程
服务端。
func main() {
// 监听
listener, _ := net.Listen("tcp", ":8080")
defer listener.Close()
// 处理请求
for {
conn, _ := listener.Accept()
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
buf := make([]byte, 1024)
n, _ := conn.Read(buf)
fmt.Println(string(buf[:n]))
_ = conn.Close()
}
客户端。
func main() {
conn, _ := net.Dial("tcp", ":8080")
// 连接服务器
defer conn.Close()
// 发送数据
_, _ = conn.Write([]byte("Hi"))
}
Http编程
服务端。
func main() {
// 处理请求
http.HandleFunc("/", handleConn)
// 监听
_ = http.ListenAndServe(":8080", nil)
}
func handleConn(w http.ResponseWriter, req *http.Request) {
_, _ = w.Write([]byte("Hi"))
}
客户端。
func main() {
resp, _ := http.Get("https://www.baidu.com")
defer resp.Body.Close()
buf := make([]byte, 10240)
n, _ := resp.Body.Read(buf)
fmt.Println(string(buf[:n]))
}
END
以上就是本文的全部内容,文档会根据自己的实际使用和各位提出的问题而不断更新。
如果觉得本文对您有一点点帮助,欢迎点赞、转发加关注,这会对我有非常大的帮助,如果有任何问题,欢迎在评论区留言,咱们下期见!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。