1. 通过HelloWorld了解Go语言的基本结构
package main
import "fmt"
func main() {
fmt.Println("Hello World go!")
}
该代码主要分为三个部分:
package main:包名,GoLand中包名默认与创建的空文件名相同,只有main包里才可以编译运行。import "fmt":导入包,其中"fmt"是一个标准库包,用于格式化输入输出。它提供了类似于C语言中printf和scanf的功能,但是更加强大和灵活(这点在后面会有体现)。func main():主程序入口。
2. 变量与常量
2.1 变量
变量声明形如:
var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
var声明的变量,Go会自动推断其类型,类似于python和C#,简单易用。
另一种声明方法形如:
f := float32(e)
g := a + "foo"
2.2 常量
在变量的基础上,将var改为const即可,形如:
const h string = "constant"
const i = 100000
3. if
与C++、java的if相似,区别在于条件不需要加括号。
另有特殊形式:
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
重点在于num := 9,可以像for一样在条件中声明变量。
注意:else if和else分支必须跟在上一个分支的} 后面,不能换行。
4. for
与C++、java的for相似,区别在于:
for后面的三个部分(例如i := 0; i < 5; i++),每个部分都可以删除。for如果后面不跟条件,其效果等同于while死循环。
5. switch
与C++、java的switch相似,区别在于:
case中不用加break,默认每个分支独立执行,相较于C++、java而言更加简易,但也有可能会使某些需要连续执行case的问题变得更加复杂。switch后面可以不写条件,而直接在case写条件,该部分几乎没有限制,相较于在switch后面必须写条件而言更加灵活。
6. 数组
var a [5]int
fmt.Println(a[4], len(a))
b := [5]int{1, 2, 3, 4, 5}
其中len(a)为获取a的长度,其余用法与C++、java相似,同样是长度固定的数组,因此写代码时更多使用的是切片。
7. 切片
s := make([]string, 3) // 构造函数,3为长度
len(s) // 返回切片长度
s = append(s, "d") // 在切片末尾添加元素
copy(c, s) // 复制切片
s[2:5] // 索引2到5的元素,不包括索引5
s[:5] // 第1个元素到索引5的元素,不包括索引5
s[2:] // 索引2的元素到末尾
fmt.Println(s)
需要注意的是,append调用后必须赋值给原切片,这点与java、C#中的append略有区别。
8. map
m := make(map[string]int) // string为index的数据类型,int为value的数据类型
m := map[string]int{"a": 1, "b": 2, "c": 3}
m["one"] = 1
delete(map, "one")
类似C#中的索引器,简单来说就是索引不局限于整数类型的无序数组,有更灵活的操作空间。
需要注意的是,map通常是无序存储。
9. range
m := map[string]int{"a": 1, "b": 2, "c": 3}
for k, v := range m {
fmt.Println(k, v) // a 1 b 2 c 3
}
for k := range m {
fmt.Println(k) // a b c(顺序不固定)
}
其中k为索引(key),v为数据(value),v可以省略。
10. 函数
func add(a int, b int) int {}
func add(a, b int) (v int, ok bool) {}
函数名后第一个括号为传参,第二个括号为返回值(不写则表示无返回值),可以有多个,但第一个是真正的返回值,第二个值通常表示错误信息。
11. 指针
func add2ptr(n *int) {
*n += 2
}
add2ptr(&n)
形式类似C++,但传参逻辑类似java:传入常值时为副本,不会修改原本的变量,传入索引则可以修改原数据。
12. 结构体
type [结构名] struct {
name string
password string
}
// 构造方法
a := user{ name:"wang", password:"1024" }
b := user{ "wang", "1024" } // 变量名可以省略
var d [结构名]
// 赋值变量
d.name = "wang"
不需要定义构造函数,有参无参都不需要,相较于C++而言更加简便。
13. 结构体方法
func ([形参名] [结构名]) checkPassword(password string) bool {}
在一般方法的关键字func后面(方法名前面)加上([形参名] [结构名]),同样可以使用指针。
14. 错误处理
// 导入包
import (
"errors"
)
func findUser(users []user, name string) (v *user, err error) {
return u, errors.New("not found")
}
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil {} // nil表示空,类似于null
一般作为第二个返回值进行传递和处理。
15. 字符串
import (
"strings"
)
a := "hello"
strings.Count(a, "l") // 返回2('h'和'e',计算第一个"l"之前的字符数)
方法很多,就不一一列举了。
16. 字符串格式化
p := point{1, 2}
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.Printf("%.2f\n", f) // 3.14,2表示位数
类似C++中的printf,但更方便,只用%v就可以表示任意数据类型(这点比C++区分%s(字符串)、%d(十进制整数)等方便太多了),还可以通过%+v、%#v、%.来改变输出形式。
17. JSON处理
import (
"encoding/json"
)
a := userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
buf, err := json.Marshal(a)
fmt.Println(buf) // [123 34 78 97](假设) 数字化序列
fmt.Println(string(buf)) // 字符串序列
var b userInfo
err = json.Unmarshal(buf, &b)
Marshal为数字化序列方法,Unmarshal为反数字化序列方法。
18. 时间处理
import (
"time"
)
now := time.Now() // 获取当前时间
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC) // 年、月、日、小时、分钟、秒、纳秒
同样有很多方法。
19. 数字解析
import (
"strconv"
)
strconv.ParseFloat("1.234", 64) // 1.234
strconv.ParseInt("111", 10, 64) // 将111转为十进制的64位数字
strconv.ParseInt("0x1000", 0, 64) // 4096
strconv.Atoi("123") // 字符串转数字
strconv.itoA(123) // 数字转字符串
ParseInt("111", 10, 64)中,10表示十进制(0表示默认十进制),64表示位大小(通常为int32或int64)。
20. 进程信息
import ( "os" "os/exec" )
fmt.Println(os.Args) // 进程信息
fmt.Println(os.Getenv("PATH"))
fmt.Println(os.Setenv("AA", "BB"))
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
os.Args是一个字符串切片([]string),它包含了程序启动时从命令行接收到的参数。os.Args[0]通常是程序的名称,而os.Args[1:]包含了传递给程序的其他参数。exec.Command函数用于创建一个新的进程来执行指定的命令。exec.Command返回一个*exec.Cmd结构体,它代表了一个正在运行的或者尚未运行的命令。CombinedOutput方法执行该命令,并返回命令的输出和执行时的错误(如果有的话)。