这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
简介
高性能,高并发;丰富标准库;完善工具链;静态链接;快速编译;跨平台;垃圾回收
开发环境
golang,集成ide
基础语法
hello world
// 声明程序是main包的一部分, 运行的入口部分
package main
// 导入标准库
import {
"fmt"
}
func main() {
fmt.Println("hello world")
}
运行:
go run example/01-hello/main.go
变量
通过var指定变量, 自动推导类型:
var a = "init"
var b,c int = 1,2
var e float64
// 使用:=声明变量
f := float32(e)
通过const指定常量, 根据上下文推导出类型:
const h = 5000
const s string = "const"
if else
if 7%2 == 0 {
...
} else if {
...
} else {
...
}
循环
go语言只有for循环
for {
...
break
}
for i := 7; i < 9; i++ {
...
}
j := 1
for j <= 3 {
...
j = j + 1
}
可以使用break和continue语句
switch
switch语句在每个case后不需要加break, 会自动跳出语句
a := 2
switch a {
case 1:
...
case 2:
...
case 3:
...
default:
...
}
switch可以取代if else语句, 实现更加清晰的条件判断
t := time.Now()
switch {
case t.Hour() < 12:
...
default:
...
}
数组
数组长度固定
var a [5]int
a[4] = 100
fmt.Println(a[4], len(a))
// 赋值
b := [5]int{1,2,3,4,5}
// 二维数组
var twoD [2][3]int
切片
切片可以认为是可变长度的数组
// 使用make构造切片
s := make([]string, 3)
s[0] = "a"
fmt.Println(s[0])
fmt.Println(len(s))
// 使用append追加元素
// 当元素数量超过容量, 会发生扩容, append会返回一个新指针, 因此append要把数组指针再赋值回去
s = append(s, "b")
s = append(s, "c", "d")
// 复制数组
c := make([]string, len(s))
copy(c, s)
// 类似python的切片操作, 但是不支持负数索引
fmt.Println(s[2:5])
fmt.Println(s[:5])
fmt.Println(s[2:])
map
hash存储
// string为key, int为value
m := make(map[string]int)
m["one"] = 1
fmt.Println(m["one"]) // 1
fmt.Println(m["unknown"]) // 0
// 第二个变量ok表示key是否存在
r, ok := m["unknown"] // 0 false
m2 := map[string]int{"one":1, "two":2}
var m3 = map[string]int{"one":1, "two":2}
range
遍历数组, 返回索引和数组的值; 遍历map, 返回key和value
nums := []int{1,2,3}
for i, num := range nums {
...
}
for _, num := range nums {
// 当不需要索引值
...
}
maps := map[string]int{"one":1, "two":2}
for k, v := range maps {
...
}
for k := range maps {
...
}
函数
// 返回类型后置, 必须声明返回类型
func add(a int, b int) int {
return a + b
}
func add2(a, b int) int {
return a + b
}
// 多个返回类型(直接声明返回变量)
func exists(m map[string]int, k string) (v int, ok bool) {
v, ok = m[k]
return v,ok
}
指针
简单支持指针, 用于对传入参数进行修改
func add2ptr(a *int) {
*a += 2
}
func main() {
num := 1
add2ptr(&n)
}
结构体
type user struct {
name string
passwd string
}
func main() {
a := user{name: "quhan", passwd: "123"}
b := user{"quhan", "123"}
c := user{name: "quhan"} // 在指定字段的情况下可以只初始化部分字段, 其它字段被初始化为默认值
c.passwd = "123"
var d user
d.name = "quhan"
d.passwd = "123"
}
// 可以通过传入指针节省开销
func checkpasswd(u *user, passwd string) bool {
return u.passwd == passwd
}
结构体方法
结构体也可以定义类似成员函数的结构体方法
type user struct {
name string
passwd string
}
func (u user) checkpasswd(passwd string) bool {
...
}
// 带指针支持对结构体内容修改
func (u *user) resetpasswd(passwd string) {
u.passwd = passwd
}
func main() {
a := user{name: "quhan", passwd: "123"}
a.resetpasswd("234")
a.checkpasswd("234") // true
}
错误处理
go语言可以通过函数的返回值进行错误处理
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")
}
字符串
-
strings库中包含了字符串的常用操作
strings.Contains(a, "ll") -
fmt库包含了常用的字符串格式化操作
// 打印并换行 fmt.Println(s,n) // 格式化, 类似于printf, %v可以表示任何变量 fmt.Printf("s=%v\n", s) fmt.Printf("p=%v\n", p) // 结构体的简单打印 fmt.Printf("p=%+v\n", p) // 详细信息打印 fmt.Printf("p=%#v\n", p) // 更详细的信息
json
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int `json:"age"` // 转化为json格式时候的名称(指定为age)
Hobby []string
}
func main() {
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
buf, err := json.Marshal(a) // 进行json编码
if err != nil {
panic(err)
}
fmt.Println(buf) // [123 34 78 97...]
// 需要转化为string字符串进行查看
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"}}
}
时间处理
time库
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库进行数字解析
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
}
实战项目-在线词典
实现
- 使用fanyi.caiyunapp.com提供的翻译api接口, 打开浏览器的开发者工具, 获取翻译api的curl格式的请求
- 使用curlconverter.com将curl格式的请求转换为对应的编程语言, 这样可以获取用go实现的对上述翻译api的调用
- 编写api请求的请求结构, 将请求结构转化为json格式, 作为api请求的请求体
- 编写api响应的响应结构, 可以使用oktools.net/json2go将json格式的响应转化为go的结构体
代码
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
type DictRequest struct {
TransType string `json:"trans_type"`
Source string `json:"source"`
UserID string `json:"user_id"`
}
type DictResponse struct {
Rc int `json:"rc"`
Wiki struct {
KnownInLaguages int `json:"known_in_laguages"`
Description struct {
Source string `json:"source"`
Target interface{} `json:"target"`
} `json:"description"`
ID string `json:"id"`
Item struct {
Source string `json:"source"`
Target string `json:"target"`
} `json:"item"`
ImageURL string `json:"image_url"`
IsSubject string `json:"is_subject"`
Sitelink string `json:"sitelink"`
} `json:"wiki"`
Dictionary struct {
Prons struct {
EnUs string `json:"en-us"`
En string `json:"en"`
} `json:"prons"`
Explanations []string `json:"explanations"`
Synonym []string `json:"synonym"`
Antonym []string `json:"antonym"`
WqxExample [][]string `json:"wqx_example"`
Entry string `json:"entry"`
Type string `json:"type"`
Related []interface{} `json:"related"`
Source string `json:"source"`
} `json:"dictionary"`
}
func query(word string) {
client := &http.Client{}
request := DictRequest{TransType: "en2zh", Source: word}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewReader(buf)
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Connection", "keep-alive")
req.Header.Set("DNT", "1")
req.Header.Set("os-version", "")
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36")
req.Header.Set("app-name", "xy")
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("device-id", "")
req.Header.Set("os-type", "web")
req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
req.Header.Set("Sec-Fetch-Site", "cross-site")
req.Header.Set("Sec-Fetch-Mode", "cors")
req.Header.Set("Sec-Fetch-Dest", "empty")
req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
}
}
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
`)
os.Exit(1)
}
word := os.Args[1]
query(word)
}