这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
Go语言基础语法
一、Go语言的特点
- 高性能、高并发
- 语法简单
- 丰富的标准库
- 完善的工具链
- 静态链接
- 快速编译
- 跨平台
- 垃圾回收
二、Go语言的结构
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
1. package main
在Go语言编写的程序中,如果只有一个文件,那package必须是main(表明其是一个可独立执行的程序),否则会报错
package定义的是包名,每一个源文件都必须在非注释的第一行指明该文件属于什么包。
2. import “fmt”
Go的import和java的import一样,是导入包,但不需要像java一样一个一个去import,go支持了花括号的导入(只用写一个import,包写在花括号里就行)
fmt是go语言的一个包,它里面实现了标准化的IO(输入与输出)的函数。
fmt.Println和java的System.out.println是一样的用法,后面的ln均表示换行。
fmt也支持和C一样的格式化输出,不过fmt的格式化是可以用%v,然后由编译器自动推导,+v可以打印出详细的结果,#v会更加详细
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2}
fmt.Printf("s=%v\n", s) // s=hello
fmt.Printf("n=%v\n", n) // n=123
fmt.Printf("p=%v\n", p) // p={1 2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
f := 3.141592653
fmt.Println(f) // 3.141592653
fmt.Printf("%.2f\n", f) // 3.14
3.func
和C一样,main函数是go程序开始执行的函数,和C不同的就是函数的定义和声明前面要加一个func
三、Go语言变量的声明
1.变量的声明
var name type
const name
其中var是声明变量的关键字,name是变量的名字,type是变量的类型(type可以不加,go是可以自动推导类型的)
const是声明常量的关键字,go的常量没有确定的类型,一般会根据上下文去自动推导
声明变量也可以使用:=
a:=1
//相当于
var a int
a = 1
var a := 1 //这会产生编译错误,var和:=重复声明了
多变量的声明
var name1, name2 type //声明同一类型的多个变量
var (
a int
b string
c []float32
d func() bool
e struct {
x int
}
)
//声明多种类型的多个变量
如果你声明了一个局部变量却没有在相同的代码块中使用它,会发生编译错误
2.变量的类型及初始化
- 整形:0
- 浮点型:0.0
- 布尔型: false
- 字符串型:""(空字符串)
以下几种特殊的变量为nil:
var a *int //指针
var a []int //数组
var a map[string] int//kv数据,和c++的map相似
var a chan int//管道,进行进程间通信的
var a func(string) int//函数
var a error //错误提示
四、Go语言的基本语法
1. 判断语句
go语言的if else语句和C++的写法类似,只不过go对于if后的判断条件是不需要加()的,而且判断条件的后面是必须有{}(如果加了(),那么在保存的时候编辑器会自动帮你去掉的)
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
2.循环语句
与C++、java等语言最大的不同的是,go语言只有for循环,没有wihle、do while循环,最简单的for循环就是在for后面什么都不写,也就相当于一个死循环,for循环同样可以使用break或continue来跳出或继续循环
package main
import "fmt"
func main() {
i := 1
for {
fmt.Println("loop")
break
}
for j := 7; j < 9; j++ {
fmt.Println(j)
}
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
for i <= 3 {
fmt.Println(i)
i = i + 1
}
}
3.条件分支语句
switch语句和C++也类似,不过也和for循环一样,switch后面是不用加()的,可以跟变量,也可以什么都不加,和C++最大的区别是不需要用break来跳出分支,它自己就可以跳出分支
package main
import (
"fmt"
"time"
)
func main() {
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
case 4, 5:
fmt.Println("four or five")
default:
fmt.Println("other")
}
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
}
4.数组
数组是一个具有编号且长度固定的元素序列,和C++的用法基本一致,可以用下标去访问数组元素,也可以使用初始值列表来初始化
var a [5]int
a[4] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
5.切片
这是go语言独有的结构(python也有,go的切片是不支持负数索引的),和C++的vecotr容器是类似的,都存有一个长度和一个容量,长度是可以任意更改的(当发生扩容时,append会返回一个全新的silce),slice拥有像python的切片一样的功能
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) // [a b c d e f]
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
good := []string{"g", "o", "o", "d"}
fmt.Println(good) // [g o o d]
6.map
和C++的map是类似的,也是key-value模型,同样支持[]的访问(得到的是value值),和C++的map不同的是,go的map是完全无序的,对其进行遍历,得到的是随机的顺序,也就是说对同一个map去遍历,可能得到不同的结果
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
fmt.Println(len(m)) // 2
fmt.Println(m["one"]) // 1
fmt.Println(m["unknow"]) // 0
r, ok := m["unknow"]
fmt.Println(r, ok) // 0 false
delete(m, "one")
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3)
7.range
相当于C++的范围for的使用
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v) // b 8; a A
}
for k := range m {
fmt.Println("key", k) // key a; key b
}
8.函数
go和其他语言不一样,变量的类型是后置的,同时go语言的函数是支持多个返回值的
package main
import "fmt"
func add(a int, b int) int {
return a + b
}
func add2(a, b int) int {
return a + b
}
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
func main() {
res := add(1, 2)
fmt.Println(res) // 3
v, ok := exists(map[string]string{"a": "A"}, "a")
fmt.Println(v, ok) // A True
}
9.指针
和C++的用法基本一致,但支持的操作很有限
func add2(n int) {
n += 2
}
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 5
add2(n)
fmt.Println(n) // 5
add2ptr(&n)
fmt.Println(n) // 7
}
10.结构体
结构体是带类型的字段的集合,和C++也基本一致,不过go多了结构体方法(将结构体变量的参数提到函数名的前面),其操作类似于类的成员函数。
package main
import "fmt"
type user struct {
name string
password string
}
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
}
11.错误处理
由于go语言天然支持函数返回多个值,所以一般直接可以在函数里返回错误信息,不像C++一样还需要异常处理,不仅能精准的定位到错误,还能直接用if else来处理错误
package main
import (
"errors"
"fmt"
)
type user struct {
name string
password string
}
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
func main() {
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
12.数字解析
字符串和数字之间的转换,在go语言中,这些都在strconv这个包下。
ParseInt(),即将字符串转换为整数,第二个参数是控制进制的,ParseFloat则将字符串转换为float型的变量。
atoi()将十进制字符串转化为数字,而itoa()将数字转化为字符串
package main
import (
"fmt"
"strconv"
)
func main() {
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) // 1.234
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}
总结
对于有C++、java、python基础的人来说,go语言的语法十分简单,很多东西是互通,同时,由于go语言是后面才诞生的,所以go呢汲取了前辈语言的的长处,还摒弃了他们的一些短处,比如直接用%v来代替所有的格式化输出,让学习成本更低了,switch自动跳出case,不用显示的写出break,一定程度上减少了代码的冗余。