特点及应用场景
- 高性能,高并发
同c++,java的高性能
不用第三方库来开发应用,标准库就可以开发高并发应用程序 - 语法简单
类似C语法
上手容易,一周就行 - 丰富的标准库 很高的稳定性
- 工具链完善
编译,等
性能测试 - 静态编译
- 快速编译
- 跨平台 各种操作系统,安卓也行,路由器
入门
语法
main包 fmt:格式化输入输出,字符串等 go run :运行
变量
go 是强类型语言 字符串:可直接加号拼接,= 比较 整型,浮点型
变量的声明
var 变量名 = xxx会自动根据xxx判断变量类型- 显示地声明:
var 变量名 int = 1 变量名 := float32(e)
常量
var改成const即可 根据使用的上下文自动确定类型
if else
if 条件 条件两边不用括号
for循环
只有这一种循环,没有while
就变量声明有点不一样
switch分支结构
switch a{
case 1:
case 2:
...
...
default:
}
不用break,默认对应上一种情况之后,执行完毕,就会退出循环
变量a可以是任意类型,字符串,结构体
switch 不接变量,也是一种写法
数组
var a [5] int 固定长度
切片
长度可变
创建切片:make
s:= make([]string,3)
追加元素:append
s = append(s,"d","e")
注意:要把append的结果赋值给原数组
slice的原理:存储了一个长度(容量)和一个指向数组的指针,在append操作的时候,若容量不够,会扩容并返回新的slice
###切片操作(同python)
s[2:5]
s[:5]
s[2:]
不包括5
不支持负数索引
map
创建空map
m := make(map[string] int)
//key的类型:string
//value的类型:int
m["one"] = 1
m["two"] = 2
fmt.Println(m)//map[one:1 two:2]
fmt.Println(len(m)) // 2
删除键值对:delete
delete(m,"one")
map是完全无序的
m2 := map[string]int{"one":1,"two":2}
var m3 := map[string]int{"one":1,"two":2}
某个没有value的key
fmt.Println(m["unknow"]) // 0
r,ok := m["unknow"] // r = 0, ok = false
//加了ok,来知晓这个key的value存不存在
range 快速遍历
若是数组,第一个是索引,第二个是值
nums := []int{2, 3, 4}
for i, num := range nums {
fmt.Println(i,num)
}
//遍历 index,num:0,2 1,3 2,4
若只有一个值,如:
for num := range nums {
fmt.Println(num)
}
//就是第一个值,这里是index
// 0 1 2
若只想要第二个值,就要用下划线
for _, num := range nums {
fmt.Println(i,num)
}
//2 3 4
若是map,则第一个是key,第二个是value
类似的,若只用一个变量,则是key的值 若只要value,则用下划线
函数
golang:变量类型是后置的 函数原生支持返回多个值 在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是真正的返回结果,第二个值是一个错误信息。类似v和ok
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
}
指针
主要用途:对传入参数进行修改
查看是否用指针的区别:
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
}
函数定义的时候是*
调用的时候用&
在计算的时候同样有解引用*
结构体
定义
type user struct{
name string
password stirng
}
初始化
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
}
结构体方法
类似于类的成员函数 示例:
//对比上面的普通函数,user的位置变了,从传入参数列表中移到了前面
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,代表这个函数可能会返回错误 error可通过errors.New("message")来创建 可以用if else 来处理错误 示例如下:
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)
}
}
字符串操作
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
}
字符串格式化
import "fmt"
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
//Println 打印多个变量并且换行
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2}
//Printf:
//%v 打印任意类型的变量
//%+v 打印详细结果
//%#v 打印更详细结果
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处理
import (
"encoding/json"
"fmt"
)
//结构体每个字段的第一个字母是大写,在go里面就是公开字段,那么这个结构体就可以用json序列化
type userInfo struct {
Name string
//若需要输出小写,可以加一个json tag 修改,如下,Age在json序列化输出后是age
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)
}
//序列化后得到数组buf
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
//反序列化到一个空的变量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"}}
}
时间处理
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
}
数字解析
字符串和数字之间的转换
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
}
进程信息
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
}