Go基础语法
内容整理自字节内部课--走进 Go 语言基础语法
1.基本框架--HelloWorld
package--import--func
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
2.基本变量和声明
字符串、整型、浮点型、布尔型
-
字符串为内置类型,可直接通过加号拼接,以及"<"">"比较
g := a + "foo" -
变量声明:主要有两种
-
var 变量名 = 值(自动推导/显式指定)
-
变量名 := 值
var a = "initial" var b, c int = 1, 2 var d = true var e float64 f := float32(e) g := a + "foo"
-
-
常量声明:将 var 改为 const(无指定类型,自动指定类型)
const s string = "constant" const h = 500000000 const i = 3e20 / h -
nil是一个预定义的标识符,用于表示指针、接口、切片、映射、通道和函数类型的零值。对于指针类型,nil表示该指针没有指向任何内存地址;对于接口类型,nil表示该接口没有实现任何方法;对于切片、映射、通道和函数类型,nil表示它们没有被初始化。
3.基本语句
-
if-else
与C++类似,但 if 后无括号,且循环体必须有括号
if 7%2 == 0 { fmt.Println("7 is even") } else { fmt.Println("7 is odd") } -
for 循环
同上,且 continue 与 break 同样适用
for n := 0; n < 5; n++ { if n%2 == 0 { continue } fmt.Println(n) } -
switch 分支结构
同上,但默认不需要每个分支加入 break,
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") }go语言中的switch支撑功能更强大,可使用任意变量类型,还可以使用 if 类型语句
t := time.Now() switch { case t.Hour() < 12: fmt.Println("It's before noon") default: fmt.Println("It's after noon") }
4. 其他数据结构
-
数组
与其他语言类似,重点在于声明语句
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) -
由于数组的长度固定,一般使用切片
-
使用make创建切片
s := make([]string, 3)good := []string{"g", "o", "o", "d"} -
可以直接用索引直接赋值
s := make([]string, 3) s[0] = "a" s[1] = "b" s[2] = "c" -
使用append追加元素,注意用法:需要将原切片作为参数,执行方法后赋值回原切片
s = append(s, "d") -
支持类似python的切片操作,但不支持负数索引
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] -
可以用copy() 方法复制切片
c := make([]string, len(s)) copy(c, s)
-
-
map
- 使用make() 创建map,或直接创建
m := make(map[string]int) m["one"] = 1 m["two"] = 2m2 := map[string]int{"one": 1, "two": 2} var m3 = map[string]int{"one": 1, "two": 2}-
使用delete() 删除键值对
delete(m, "one") -
直接用 [] 进行查询,取值等操作
fmt.Println(len(m)) // 2 fmt.Println(m["one"]) // 1 fmt.Println(m["unknow"]) // 0 r, ok := m["unknow"] -
map的遍历是近似随机的
-
range
-
对于数组,返回值第一个位置为索引(可用_代替),第二个位置为对应值
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 } } -
对于map,返回值第一个为key,第二个为value
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 }
-
5. 函数
-
注意golang中,返回值类型后置
func add(a int, b int) int { return a + b } -
golang支持返回多值,因此在一般业务逻辑中,一般返回两个值,第一个为运算结果,第二个为执行情况(报错信息)
func exists(m map[string]string, k string) (v string, ok bool) { v, ok = m[k] return v, ok }
6. 指针
-
与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 }
7. 结构体
-
与C语言类似,使用type关键字声明
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 } -
结构体方法(类似Java中的类成员函数),可通过结构体对象自身访问内部元素或修改内部元素(需要用到指针)
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 }
8. 错误处理
-
需要导入errors包
-
在定义方法时,加入一个error类型返回值,error对象通过errors.New("error Message") 创建
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) } }
9.字符串操作
-
需要导入strings包
-
常见方法如下:
func main() { a := "hello" fmt.Println(strings.Contains(a, "ll")) // true fmt.Println(strings.Count(a, "l")) // 2----字符串计数 fmt.Println(strings.HasPrefix(a, "he")) // true 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----一个中文可能对应多个字符 } -
TrimSuffix(‘xxx’)去掉后缀
-
字符串格式化
-
Printf()(可以使用%占位表示任意类型变量)
-
+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
-
-
字符串和数字转换
-
需导入strconv包
-
操作如下
f, _ := strconv.ParseFloat("1.234", 64) fmt.Println(f) // 1.234 //10表示进制,64表示精度 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
-
10.json操作
-
需要导入encoding/json包
-
通过json.Marshal() 方法类序列化一个结构体对象,结果为一个十六进制编码数组,需要经过String类型转换才能正确输出
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}} buf, err := json.Marshal(a) if err != nil { panic(err) } fmt.Println(buf) // [123 34 78 97...] fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]} -
序列化后的结果可以通过Unmarshal() 方法,反序列化到一个空变量中
var b userInfo 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"}} -
可以在结构体的变量定义中加上tag(如下),即可使得序列化后打印的字符串中字段名为对应tag
type userInfo struct { Name string Age int `json:"age"` Hobby []string }
11. 事件处理
-
需要导入time包
-
具体操作如下:可进行的操作包括:
- 使用time.Now()获取时间
- 对时间格式化(注意特定执行格式)
- 使用x.Year/Month/Day/Hour/Minute获取对应信息
- 使用x.Sub()方法获取时间差,该时间差可以通过 Minute()和Seconds()方法获得相差的分数和秒数
- 使用Parse()方法解析时间(将时间字符串转为time对象)
- 通过x.Unix()获取时间戳
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 }
12.进程信息
-
如下,知识有限,解读略
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")) buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput() if err != nil { panic(err) } fmt.Println(string(buf)) // 127.0.0.1 localhost }