这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
go语言基础
go语言的特性
1.高性能,高并发
2.语法简单,学习曲线平缓
3.丰富的标准库
4.完善的工具链
5.静态链表
6.快速编译
7.跨平台
8.垃圾回收
go语言基础语法
第一个hello world程序
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
main包是程序的入口包,即为程序的入口文件。“fmt”是标准库中的一个包,主要功能有控制屏幕的输入输出,格式化字符串等。
变量的声明
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))
}
与其他编程语言不同,go先声明变量名,后面再跟变量类型。也可采用:=的方式自动分配变量类型。
数组与切片
package main
import "fmt"
func main() {
var a [5]int
a[4] = 100
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))
}
在真实的业务逻辑下go很少用数组去声明,因为一般长度都是固定的。go通常采用切片去定义一个可动态扩容的数组。感觉类似于java中的StringBuffer。
range快速遍历
package main
import "fmt"
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
}
}
}
对于数组range会返回两个值,第一个是下标,第二个是对应位置的value,如果不需要返回值,可用_来代替。range语法比较简洁,通常用于快速遍历数组或切片元素。
指针
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
}
go对指针的操作相对较少,与初学C语言时遇到的困难差不多,要弄清楚传入的到底是实参还是形参,操作与C中的指针类似。
结构体方法
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
}
类似于java中的类成员方法。
错误处理
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)
}
}
如果程序可能出现运行错误,在函数的返回值中可以加一个error。不同于java中的异常处理,go能够更清晰的知道哪个函数出现了错误。所以在接受返回值的时候要定义一个err用于接受错误的返回值。
json操作
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"}}
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"]}
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(buf))
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"}}
}
首先要保证结构体中的每个字段的首个字母要大写,以此来保证用json.Marshal()序列化的成功,序列化之后存于一个Byte数组,用string做强制类型转化方便查看。也可用json.Unmarshal()做反序列操作。
数字解析
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
}
golang中strconv包实现数字和字符串的转换。 Atoi将字符串转换为数字,Rtoa实现反向操作。
进程信息
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
}
os.Getenv()和os.Setenv()用于获取和写入环境变量。
总结
go语言上手速度比较快,与其他语言相比都有不少共同点,所以学习起来较为轻松,同时其语法比较简洁明了,还省去了垃圾回收机制,能够使开发人员更专注于逻辑的开发编写。