课程笔记 - 基础语法学习 | 青训营笔记

203 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天


基础语法

日期

在 golang 中,日期格式化的方式与其他传统语言的 YYYY-MM-dd HH:mm:ss 略有不同,golang 的格式化字符串是一串写在源码里的日期原点(使用时必须非常精确) 2006-01-02-2 15:04:05(经资料查找发现该时间节点应该是 golang 诞生的日期,说实话挺令人无语的)

以下是日期序列化与反序列化常用方法

now := time.Now()
fmt.Println(now)
fmt.Println(now.Format("2006-01-02-2 15:04:05"))
//now.Sub() 返回 now -> param 的持续时间
t2, err := time.Parse("2006-01-02-2 15:04:05", "2023-01-13 12:08:09")
if err != nil {
   panic(err)
}
fmt.Println(t2.UnixMilli())

对象与json

golang 中的对象与 c、c++ 等语言类似,采用结构体的方式来声明与定义,其格式如下

type User struct {
   name string
   age  int
}

在 golang 中,对象与 json 的转换不像 java 那么麻烦,golang 原生库 json 就支持了二者之间的转化,你还可以在定义结构体时额外指定 json 化后的字段名称。

type UserInfo struct {
   // 大写代表是公开字段
   Name string `json:"name"`
   Age  int    `json:"name"`
}
userInfo := UserInfo{"IllTamer", 6}
bytes, err := json.Marshal(userInfo)
if err != nil {
   panic(err)
}
fmt.Println(string(bytes))
var info UserInfo
err = json.Unmarshal(bytes, &info)
if err != nil {
   panic(err)
}
fmt.Println(info)

指针

golang 中的指针与 c 中的指针类似,在传递参数时如若不使用指针,则传递的是参数的拷贝值(对象方法也同理)。因此,我们在定义函数时应明确区分参数的使用场景:什么时候需要做到参数隔离、什么时候又需要传递指针避免大数据拷贝消耗内存资源,都是值得思考的问题。

// 带指针才能修改值,否则仅修改局部变量
func (user *User) canSet(name string) {
   user.name = name
}

slice 与 array

在本人粗浅的理解中,golang 的切片与数组相差其实不大。数组在创建时就确定了长度,无法在原有基础上扩容;而切片内部封装了数组,它通过收集多个数组地址实现所谓的'拓展'。所以换句话说,数组是切片实现的原理。(以下是切片在 golang 中的定义)

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

golang 中的切片与 python 的切片类似,是一种非常灵活的数据结构,以下时其常用 api 的使用

var s = make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println(s)

s = append(s, "d")
fmt.Println(s)

s2 := make([]string, len(s))
copy(s2, s)
fmt.Println(s2)

fmt.Println(s[0])
fmt.Println(s[0:2])

作业

猜数游戏 - 用 fmt.Scanf 简化数字输入

rand.Seed(time.Now().UnixNano())
secret := rand.Intn(100)
fmt.Println("Number is", secret)
fmt.Println("Input start")

var num = -1
for {
   _, err := fmt.Scanf("%d", &num)
   if err != nil {
      panic(err)
   }
   switch {
   case num > secret:
      fmt.Println("Lower")
   case num < secret:
      fmt.Println("Bigger")
   default:
      fmt.Println("Yes")
      break
   }
}

查单词 - 额外支持一种单词 api

经比较筛选后我选择支持 bing 翻译,并将两种查单词逻辑中的通用部分提取成为 reqAndGetResp 方法,以实现代码复用:

type BingTransResponse []struct {
   Translations []struct {
      Text string `json:"text"`
   } `json:"translations"`
}

func bingTrans(word string) (respStr string) {
   var data = strings.NewReader("&fromLang=en&text=" + word + "&to=zh-Hans&token=tLfmQEEO8dcKBoFgOp2OKL6ahhJawxLk&key=1673711146402")
   req, err := http.NewRequest("POST", "https://www.bing.com/ttranslatev3?isVertical=1&&IG=8877E8001BEE470BBF67A041F2CE0522&IID=translator.5024.1", data)
   if err != nil {
      log.Fatal(err)
   }
   req.Header.Set("content-type", "application/x-www-form-urlencoded")
   req.Header.Set("cookie", "MUID=299D5EE88C99608232D34C7B8D596161; SRCHD=AF=NOFORM; SRCHUID=V=2&GUID=175ADA4DFC6A486298C5684D25C1C16E&dmnchg=1; _SS=SID=01C633377388618D042E21AE72806031; _tarLang=default=zh-Hans; _TTSS_IN=hist=WyJlbiIsImF1dG8tZGV0ZWN0Il0=; _TTSS_OUT=hist=WyJ6aC1IYW5zIl0=; SRCHHPGUSR=SRCHLANG=zh-Hans&WTS=63809307946&HV=1673711155; ANON=A=A4B66EF0B16C53D68CFF9325FFFFFFFF&E=1bd8&W=1; NAP=V=1.9&E=1b7e&C=NPwRktC3_8rqb1O14qL9_sf8NWmXgCwaIdFwv8Mpeodc41ovRiI7JA&W=1; PPLState=1; KievRPSSecAuth=FABSBBRaTOJILtFsMkpLVWSG6AN6C/svRwNmAAAEgAAACDWqcHGqpzZGEARNx9aHWTVs4DW5gp7Wzo0nSlnKoUbgqkqnYujSHeuLotPFbhm/KFos7tO2uBVmwasqRRzagEobWlh4kWFyr4KDE9OqGuxpVcbyjBPJGK6c1y3hd2QkIv8m2p7k8/rSainkf76BCOHAHJ1/GoWyVGeH5V2egRntzpvXN6c9bUIWl8bxOVnUDMcf+Xnx5J84VcgQRcKP0VjKAmPRnj77CP1VmvVET2CAG1KD/+cCzSs9/exJ+XnnYcs91BUl0PRggXmch2zYm5OppW94F4UxVcTg9nHwY5QRofFQ3ghpj2VsSuTJbrlRZ2ASywsd79JhpZSNK8GyYhqMw0vxRXeRGp+dZZM7KoJa4Hb+edJJbU8hQnXIwqYJkJWofYvay42mOnxvyoRRNQI+h89IHQa5ob7UxkQ0cESnLxErsCZR1FFdG8yNzZFx7qZxbMPNC9cHrIs8PMjoCV7G8gS51RU7r+/9qYS4wvNxL+DQvQC3GWAQWXC56qyyPk0IAr8aIw/Ks/jTcsDE45yiyBJDKjpojx8IQUSymCK7YDtntboRZIAz36UXvkwHznlBeF/UMphwi0u6oGqOQ723SzlOIwEVWjyOYyg/Flcfw11DqiBFsHt2NnVtcqH8WTfqBjuWl/ji7bnIDmYiO+yc2xV4ajoTGzjIeDIwupwhzCO0bJxUoox/XAbrHZrO5UWhGsnQtianWQIIg7It95U1R+snJyRWD1Opwqyeufne6cVXqIiebUNVdsHXVgjRB39Zv8dOkU9IEyC+jUArqyRYsShDQ1MYjJgpkdBAt34NJa/tC6jB8J8uApBGpjXoI2HDc1xghgiub7eXQvuy8XOP+MLAx4+SH3Rzxz5p7Z+ukF97BxqKWMeE1MDUcrrAdY7XxTBCVrP92hazmKBw20x0WYcI9KtsgD8pQh0oM9Ngz895MRJ70fY4Q27qquLl5xMypvFC8+D3FMxBLiSCLZBfX/PH7spZLJUGXKzgquMCXZXapEkRmGxKkAkqMC0nHLER8ctjceLgv5zIKuBMOjhgNoO/vAq4KdpIjIpuMNuZQuyrOhVZdiwR/FgY+fkVSFoJExUzbChLujlKkFxr4KLxLFlx2+0YBqc3drD0M3KAC7V7m2kiwbOzZc4tk4jvIwWV8vfssJsFUa1foRjTbgmuqH+DA6Iym/xgthUGky8VRk6nS6H91KYVWH7/YHVT8xkyNhouXFYkiUzgpLKQsstR/NCME9y3HAARvJzG+Z4QTCii/VnazzMTBFX+JG3Z2rN96xiWNlZ+XrfSqNyV/SHfFVjQgY+FBaqBdZ7hG7Pb2cnjzFE6HivbyvI6DwiUuHg+gJGubODlC0yHsm+yKjm4UUjW1ZbNNpp7QR55cxQ9R7ovFebIeXYGdxQAL1WjOKnaBmOU0YJa8zqQR9pn10Y=; _U=1FbNfDL3xYHxUTQVm_dyCme-4tPq_nnx_KeLZd7a_CWtiOvp7eFmy05bi0uvx-emRpbqI56iKrvIqnx4HaE9Te9Tdi3EjfEUfgy81rq0PFLAgw2WDa4_uulB84gSAYgITWRuAhmKn27xnLBMo3F6dldWqM12rKWfo3qhbDiaNGhqhyEWzzrA10_Aq-mCutBEFGBwq3Htaoirhn0QJRF961A; WLS=C=f3f979115dd16793&N=%e5%9f%b9%e9%92%8a; SRCHUSR=DOB=20230114&T=1673711146000&TPC=1673711155000&POEX=W; WLID=1SnS7mASIsnN7EiYT9dSEfL3t4NKUulQ5I+lrIRLN7LMxT/gXJ77S4KuyYMNzFPwCzgdDO05foD5+YIMdbcWzG/Qn+eFpa8WTeU3qxB22MI=; SUID=A; ipv6=hit=1673714757351&t=4")
   req.Header.Set("user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")

   bodyText := reqAndGetResp(req)
   var response BingTransResponse
   err = json.Unmarshal(bodyText, &response)
   if err != nil {
      log.Fatal(err)
   }
   return fmt.Sprint(word, " ", response[0].Translations[0].Text)
}
func reqAndGetResp(req *http.Request) (bodyText []byte) {
   client := &http.Client{}
   resp, err := client.Do(req)
   if err != nil {
      log.Fatal(err)
   }
   defer func(Body io.ReadCloser) {
      err := Body.Close()
      if err != nil {

      }
   }(resp.Body)
   bodyText, err = io.ReadAll(resp.Body)
   if err != nil {
      log.Fatal(err)
   }
   if resp.StatusCode != 200 {
      log.Fatal("status:", resp.StatusCode, "body", string(bodyText))
   }
   return bodyText
}

查单词 - 两种查询同时进行返回更快结果

这一点其实很好做,结合老师在课中讲述的 socks5 代理实际通信部分的内容,将两个查单词 api 分别在两个 goroutine 中启动,并创建上下文进行等待。任意一 api 返回查询结果后进行输出即可

if len(os.Args) != 2 {
   log.Println("Usage: ./02 <word> (Auto choice faster api)")
   os.Exit(1)
}
var word = os.Args[1]

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

var respStr = ""
go func() {
   respStr = caiyunTrans(word)
   cancel()
}()
go func() {
   respStr = bingTrans(word)
   cancel()
}()
<-ctx.Done()

fmt.Println(respStr)