一、Go基础语法
语言结构
main.go
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
第一行,表示该文件属于main包。在 Go 语言中,main包是一个特殊的包,它包含了程序的入口点。
第三行导入了一个名为fmt的包。fmt包提供了格式化输入输出的功能,它包含了向控制台输出内容的函数。
在main函数中,使用了fmt.Println函数来将字符串"hello world"输出到控制台。Println函数会在输出后自动换行。
运行程序 go run main.go
编译程序 go build main.go
变量
声明变量的两种方式:
var identifier typevar b, c int = 1, 2:=f := float32(e)
package main
import (
"fmt"
"math"
)
func main() {
var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e)
g := a + "foo"
fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
fmt.Println(g) // initialapple
const s string = "constant"
const h = 500000000
const i = 3e20 / h
fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}
if else
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")
}
循环
在go里面设有while循环、do while循环,只有唯一的一种for循环
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
switch
在c++里面,switch case如果不显示加break的话会然后会继续往下跑完所有的case,
在go语言里面的话不需要加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")
}
}
/*
two
It's after noon
*/
数组
Go 语言数组声明需要指定元素类型及元素个数;
var variable_name [SIZE] variable_type
func main() {
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)
}
/*
get: 0
len: 5
[1 2 3 4 5]
2d: [[0 1 2] [1 2 3]]
*/
切片
与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大;
make创建切片;append追加元素;
声明一个未指定大小的数组来定义切片var identifier []type
使用make var slice1 []type = make([]type, len)
package main
import "fmt"
func main() {
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]
}
map
golang中的map是完全无序
package main
import "fmt"
func main() {
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)
}
range
用于快速遍历slice;map;
返回第一个值为索引,第二个为对应位置值,不需要索引可以用下划线忽略
func main() {
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
fmt.Println(sum) // 9
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
}
}
函数
- 变量类型后置
- 支持返回多个值
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
}
指针
go里面也支持指针。相比C和C++里面的指针,支持的操作很有限。
指针的一个主要用途就是对于传入参数进行修改。
package main
import "fmt"
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
}
结构体
- 可以用结构体名称初始化结构体变量
- 用键值对指定初始值
package main
import "fmt"
type user struct {
name string
password string
}
func main() {
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
fmt.Println(a, b, c, d) // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
fmt.Println(checkPassword(a, "haha")) // false
fmt.Println(checkPassword2(&a, "haha")) // false
}
func checkPassword(u user, password string) bool {
return u.password == password
}
func checkPassword2(u *user, password string) bool {
return u.password == password
}
结构体方法
- 将结构体类型参数写在函数前
- 不带指针操作的为一个拷贝,无法对结构体进行修改
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
}
错误处理
在函数里面,我们可以在那个函数的返回值类型里面,后面加一个error,就代表这个函数可能会返回错误 那么在函数实现的时候,return需要同时return两个值,要么就是如果出现错误的话,那么可以return nil和一个error。如果没有的话,那么返回原本的结果和nil
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)
}
}
字符串
基础操作
依次使用了 strings 包中的以下函数和方法:
- Contains:判断字符串 a 是否包含子串 "ll",结果为 true。
- Count:统计字符串 a 中出现子串 "l" 的次数,结果为 2。
- HasPrefix:判断字符串 a 是否以 "he" 开头,结果为 true。
- HasSuffix:判断字符串 a 是否以 "llo" 结尾,结果为 true。
- Index:查找子串 "ll" 在字符串 a 中第一次出现的位置,结果为 2。
- Join:将字符串切片 {"he", "llo"} 用 "-" 连接起来,结果为 "he-llo"。
- Repeat:将字符串 a 重复两次,结果为 "hellohello"。
- Replace:将字符串 a 中的 "e" 替换为 "E",-1 表示替换所有匹配项,结果为 "hEllo"。
- Split:将字符串 "a-b-c" 按照 "-" 分割成字符串切片,结果为 ["a" "b" "c"]。
- ToLower:将字符串 a 转换为小写字母形式,结果为 "hello"。
- ToUpper:将字符串 a 转换为大写字母形式,结果为 "HELLO"。
- len:求字符串 a 和 b 的长度分别为 5 和 6。
package main
import (
"fmt"
"strings"
)
func main() {
a := "hello"
fmt.Println(strings.Contains(a, "ll")) // true
fmt.Println(strings.Count(a, "l")) // 2
// HasPrefix tests whether the string s begins with prefix.
fmt.Println(strings.HasPrefix(a, "he")) // true
// HasSuffix tests whether the string s ends with suffix.
fmt.Println(strings.HasSuffix(a, "llo")) // true
fmt.Println(strings.Index(a, "ll")) // 2
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
fmt.Println(strings.Repeat(a, 2)) // hellohello
fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo
fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
fmt.Println(strings.ToLower(a)) // hello
fmt.Println(strings.ToUpper(a)) // HELLO
fmt.Println(len(a)) // 5
b := "你好"
fmt.Println(len(b)) // 6
}
格式化
%v打印任意类型变量
%+v打印详细信息
%#v打印更加详细信息
package main
import "fmt"
type point struct {
x, y int
}
func main() {
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
}
JSON处理
- 结构体每个字段第一个字母大写
- json.Marshal()序列化
package main
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
func main() {
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
// 将 a 编码为 JSON 数据,并将结果存储在 buf 变量中
buf, err := json.Marshal(a)
if err != nil {
panic(err)
}
// 打印 buf 变量的值,它是一个字节数组
fmt.Println(buf) // [123 34 78 97...]
// 打印 buf 变量的字符串形式,它符合 JSON 格式
fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
// 将 a 编码为格式化后的 JSON 数据,并将结果存储在 buf 变量中
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(buf))
var b userInfo
// 将 buf 变量中的 JSON 数据解码为 b 变量,并将其存储在 b 变量中
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}
输出结果
[123 34 78 97 109 101 34 58 34 119 97 110 103 34 44 34 97 103 101 34 58 49 56 44 34 72 111 98 98 121 34 58 91 34 71 111 108 97 110 103 34 44 34 84 121 112 101 83 99 114 105 112 116 34 93 125]
{"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
{
"Name": "wang",
"age": 18,
"Hobby": [
"Golang",
"TypeScript"
]
}
main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
时间处理
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36
diff := t2.Sub(t)
fmt.Println(diff) // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) // true
//获取时间戳
fmt.Println(now.Unix()) // 1648738080
}
数字解析
strconv包:字符串与数字转换方法
将字符串 "0x1000" 转换为 int64 类型的数值,使用了 ParseInt 函数,第二个参数是 0,表示自动检测字符串开头的前缀,如果是 "0x" 或者 "0X",则表示这是一个十六进制数,如果是 "0",则表示这是一个八进制数,否则默认为十进制数。
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
}
进程信息
使用os.Args获取程序启动时传入的命令行参数,并打印。
使用os.Getenv获取环境变量PATH的值,并打印。
使用os.Setenv设置环境变量AA的值为BB。
根据操作系统不同,通过exec.Command执行grep或findstr指令,查找hosts文件中包含127.0.0.1的行,并获取输出。
-
在Linux中使用grep指令
-
在Windows中使用findstr指令
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
// go run example/20-env/main.go a b c d
fmt.Println(os.Args) // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go- //build3406981276/b001/exe/main a b c d]
fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
fmt.Println(os.Setenv("AA", "BB"))
// linux
// buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
// windows
cmd := exec.Command("findstr", "127.0.0.1", "C:\\Windows\\System32\\drivers\\etc\\hosts")
buf, err := cmd.Output()
if err != nil {
panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1 localhost
}