go基础 | 青训营笔记

296 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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
}

可以使用breakcontinue语句

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)
}
​