go语言入门与实战 (下)| 青训营

go语言入门与实战 (下)| 青训营

这是我在字节跳动青训营学习的第5天,也是我参加《第六届青训营笔记伴读》的第二篇笔记

概要

本文主要包括上文未写完的基础语法,以及一些实战案例

基础语法

1. 错误处理

go语言里可以用一个单独的返回值来传递错误信息,只需要在函数的返回值类型里面加一个error,代表这个函数可能返回错误,在实现的时候,return需要返回两个值,一个是函数的原来的结果,一个是error,这样能很清晰的知道哪个函数返回了错误,,并且能用减简单的if else来处理错误,但同时也带来一个问题(对我而言),大量的if语句来判断错误,影响了代码可读性

go 复制代码
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")

字符串操作

go语言标准库strings包里有很多常用的字符串工具函数

  • contanis 判断一个字符串里是否包含另一个字符串
go 复制代码
fmt.Println(strings.Contains("hello","ll") )  //true
  • count 统计字符串中出现的次数
go 复制代码
fmt.Println(strings.Count("hello","ll") )  //1
  • index 查找某个位置的字符串
go 复制代码
fmt.Println(strings.Index("hello","ll") )  //2
  • join 连接多个字符串
go 复制代码
fmt.Println(strings.Join([]string{"he","llo"},"-" )) //he-llo

*repeat 重复多个字符串

go 复制代码
fmt.Println(strings.Repeat("hello",2) //hellohello
  • replace 替换字符串
go 复制代码
fmt.Println(strings.Replace("hello","e","E",-1)) //hEllo

*len 获取字符串长度,中文长度与英文不一样

go 复制代码
fmt.Println(len("hello")) //5
fmt.Println(len("你好")) //6

字符串格式化

在标准库FMT包里有很多字符串格式相关的方法,比如printf类似于c语言中的printf函数,不同的是,在golang中,你可以用%v来打印任意类型 的变量,%+v可以打印详细结果,%#v更详细

go 复制代码
type point struct{
    x,y int
}
s:="hello"
n:=123
p := point{1,2}
fmt.Printf("s=%v\n",s) //s=hello
fmt.Printf("n=%v\n",n) //n=123
fmt.Printf("p=%+v\n",p) //p={x:1 y:2}
fmt.Printf("p=%#v\n",p) //p=main.point{x:1, y:2}

JSON处理

序列化

go语言里的JSON操作非常简单,对于一个已有的结构体,我们可以什么都不做,只要保证每个字段的第一个字母是大写的,也就是公开字段,这个结构体就能用JSON.marshal去序列化,变成一个JSON字符串,我们可以用json tag等语法来修改输出JSON结果里面的字段名

反序列化

使用JSON.Unmarshal就可以实现反序列化

代码实现

go 复制代码
type userInfo struct {  
Name string  
Age int  
Hobby []string  
}  
  
func main() {  
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"golang", "java"}}  
buf, err := json.Marshal(a)  
if err != nil {  
panic(err)  
}  
fmt.Println(buf) //16进制编码  
fmt.Println(string(buf)) //{"Name":"wang","Age":18,"Hobby":["golang","java"]}  
  
//反序列化  
var b userInfo  
err = json.Unmarshal(buf, &b)  
if err != nil {  
panic(err)  
}  
fmt.Printf("%v\n", b)   //{wang 18 [golang java]}

}

时间处理

go语言里最常用的就是time.now()来获取当前时间,也可以用time.date构造一个带时区的时间,可以用.sub去对两个时间进行减法,得到一个时间段,时间段又可以得到时分秒

在和某些系统交互的时候,我们经常会用到时间戳,可以用.UNIX来获取时间戳,time.format time.parse

go 复制代码
func main() {  
    now := time.Now()  
    fmt.Println(now)   //2023-07-29 11:02:48.3033439 +0800 CST m=+0.002110601
  
    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.Minute())  //2022 25
    fmt.Println(t.Format("2006-01-02 15:04:05"))   //2022-03-27 01:25:36
    
    diff := t2.Sub(t)  
    println(diff)   //3900000000000
    
    println(diff.Minutes())  //+6.500000e+001
    t3, _ := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")  
    println(t3 == t)  //true
    println(now.Unix())  //1690599768
}

数字解析

在go语言中,关于自付出啊内核数字类型之间的转换都在STRconv这个包下,这个包名是string convert两个单词的缩写,

我们可以用parseInt或者parseFLoat来解析一个字符串

可以用Atoi把一个十进制字符串转成数字,itoA把数字转成字符串,如果输入不合法,这些函数都会返回error

go 复制代码
func main() {  
f, _ := strconv.ParseFloat("1.234", 64)  
fmt.Println(f)  //1.234
n, _ := strconv.ParseInt("111", 10, 64)  
fmt.Println(n)   //111
  
n2, _ := strconv.Atoi("123")  
fmt.Println(n2)   //123
  
n3, err := strconv.Atoi("AAA")  
if err != nil {  
    fmt.Println(err)  //strconv.Atoi: parsing "AAA": invalid syntax
    }  
fmt.Println(n3)  //0
}

实战--在线词典(火山翻译)

用户可以在命令行里查询一个单词,我们通过调用第三方API查询到单词的翻译并打印出来

抓包

打开火山翻译网页,找到用来查询单词的请求,

这是一个post请求,请求的header相当复杂,但其实需要header的就几个,它的请求里有四个参数分别是翻译来源,单词,原始语言,目标语言

我们需要在golang里发送这个请求,因为这个请求比较复杂, 手写代码比较麻烦,我们可以右键复制这个url,然后打开curlconverter.com/go/ ,将复制好的url粘贴进去,它会自动帮我们生成请求代码

在生成的代码中帮我们创建了一个HTTP Client,接下来是构造post请求,用到了HTTP.NewRequest,第一个参数是请求方法POST,第二个参数是url,第三个参数是bodybody因为可能很大, 为了支持流式发送,是一个只读流,我们用strings.NewReader把字符串转换成流,接下来就是对HTTP request设置header,设置完成后,调用client.do(request)发送请求,若失败的话error会返回非nilresponseHTTP状态码,响应头,响应体(body),body同样是一个流,为了避免资源泄露,需要加一个defer来手动关闭这个流,defer会在函数运行结束后执行,接下来就是用ioutil.ReadAll来读这个流,这样我们就得到了整个body

但目前我们的输入是固定的,我们的目标是获取用户输入,然后拼接url,此时需要用到JSON的序列化,在golang中,我们需要生成一段JSON,常用的方式是先构造一个结构体,这个结构体和我们需要生成的JSON结构是一一对应的,requestBody中包含四个字段,分别对应四个参数

go 复制代码
type requestBody struct {  
Source string `json:"source"`  
Words []string `json:"words"`  
SourceLanguage string `json:"source_language"`  
TargetLanguage string `json:"target_language"`  
}  

之后我们从命令行读入用户输入的数据,创建一个结构体,调用JSON.Marshal得到序列化的字符串,但这里是个字符数组,所以我们把strings.NewReader变成bytes.NewReader,至此我们的请求构造完成

go 复制代码
var sourceStr string  
fmt.Scanf("%v", &sourceStr)  

request := requestBody{  
Source: "youdao",  
Words: []string{sourceStr},  
SourceLanguage: "zh",  
TargetLanguage: "en",  
}  
buf, err := json.Marshal(request)  
if err != nil {  
log.Fatal(err)  
}  
var data = bytes.NewReader(buf)  

接下来我们解析响应数据,同样要写一个结构体,把返回的JSON数据反序列化到结构体里面,但这个API返回的结构非常复杂,如果要一一定义结构体字段,非常繁琐且容易出错,,我们可以打开oktools.net/json2go 将json字符串粘贴进去,直接生成对应的结构体

go 复制代码
type DictResponse struct {  
Details []struct {  
Detail string `json:"detail"`  
Extra string `json:"extra"`  
} `json:"details"`  
}  
  
type DictResponseData struct {  
Result []struct {  
Ce struct {  
Basic struct {  
Explains []struct {  
Text string `json:"text"`  
Pos string `json:"pos"`  
Trans string `json:"trans"`  
} `json:"explains"`  
} `json:"basic"`  
} `json:"ce"`  
} `json:"result"`  
}  

然后我们定义一个结构体对象,用JSON.Unmarshal把body反序列化到结构体里面,提取出翻译的结果

go 复制代码
var dictResponse DictResponse  
err = json.Unmarshal(bodyText, &dictResponse)  
if err != nil {  
log.Fatal(err)  
}  

item := dictResponse.Details[0]  
jsonStr := item.Detail  //获取到需要的数据对应的json字符串

var myData DictResponseData  
err2 := json.Unmarshal([]byte(jsonStr), &myData)  //将json字符串解析为结构体
if err != nil {  
log.Fatal(err2)  
}  

//遍历输出结果
for _, item := range myData.Result[0].Ce.Basic.Explains {  
fmt.Println(item.Text, item.Pos, item.Trans)  
}  

完整代码如下

go 复制代码
package main  
  
import (  
"bytes"  
"encoding/json"  
"fmt"  
"io"  
"log"  
"net/http"  
)  
  
type requestBody struct {  
Source string `json:"source"`  
Words []string `json:"words"`  
SourceLanguage string `json:"source_language"`  
TargetLanguage string `json:"target_language"`  
}  
  
type DictResponse struct {  
Details []struct {  
Detail string `json:"detail"`  
Extra string `json:"extra"`  
} `json:"details"`  
}  
  
type DictResponseData struct {  
Result []struct {  
Ce struct {  
Basic struct {  
Explains []struct {  
Text string `json:"text"`  
Pos string `json:"pos"`  
Trans string `json:"trans"`  
} `json:"explains"`  
} `json:"basic"`  
} `json:"ce"`  
} `json:"result"`  
}  
  
func main() {  
var sourceStr string  
fmt.Scanf("%v", &sourceStr)  
  
client := &http.Client{}  
request := requestBody{  
Source: "youdao",  
Words: []string{sourceStr},  
SourceLanguage: "zh",  
TargetLanguage: "en",  
}  
buf, err := json.Marshal(request)  
if err != nil {  
log.Fatal(err)  
}  
var data = bytes.NewReader(buf)  
req, err := http.NewRequest("POST", "https://translate.volcengine.com/web/dict/detail/v1/?msToken=&X-Bogus=DFSzswVLQDGu/0rktHkdsVXAIQ2c&_signature=_02B4Z6wo00001GPw-CAAAIDBAPo4Swy4vuBj8PyAAHxAGHmhE0NX05JYqqJdK-F2Ap7KJ58xWV5eq8eATV4u-z0JqSXiLFQZybDD-aDAJjNfsugGJrCKUNSdhUsuxzCVe.jSB25inFNEKLnub6", data)  
if err != nil {  
log.Fatal(err)  
}  
req.Header.Set("authority", "translate.volcengine.com")  
req.Header.Set("accept", "application/json, text/plain, */*")  
req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en-GB-oxendict;q=0.8,en;q=0.7")  
req.Header.Set("content-type", "application/json")  
req.Header.Set("cookie", "x-jupiter-uuid=16906005435166114; i18next=zh-CN; s_v_web_id=verify_lknfwwif_pHxg2GVe_OCxI_4sgR_9BL8_D8H2bs3fmW7Z; ttcid=a76d32e7cc444ad19882cdd71373d9db41; referrer_title=API%E6%8E%A5%E5%85%A5%E6%B5%81%E7%A8%8B%E6%A6%82%E8%A7%88--%E6%9C%BA%E5%99%A8%E7%BF%BB%E8%AF%91-%E7%81%AB%E5%B1%B1%E5%BC%95%E6%93%8E; isIntranet=-1; ve_doc_history=4640; __tea_cache_tokens_3569={%22web_id%22:%227261074170329646650%22%2C%22user_unique_id%22:%227261074170329646650%22%2C%22timestamp%22:1690600578906%2C%22_type_%22:%22default%22}; tt_scid=9R.7CAfywmjjrkboy0HjKJbKCusQ3eixBF3FgyTVVRAi1qw236zULAW.m2uueq797a09")  
req.Header.Set("origin", "https://translate.volcengine.com")  
req.Header.Set("referer", "https://translate.volcengine.com/?category=&home_language=zh&source_language=detect&target_language=en&text=%E7%AC%A8%E8%9B%8B")  
req.Header.Set("sec-ch-ua", `"Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"`)  
req.Header.Set("sec-ch-ua-mobile", "?0")  
req.Header.Set("sec-ch-ua-platform", `"Windows"`)  
req.Header.Set("sec-fetch-dest", "empty")  
req.Header.Set("sec-fetch-mode", "cors")  
req.Header.Set("sec-fetch-site", "same-origin")  
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36")  
resp, err := client.Do(req)  
if err != nil {  
log.Fatal(err)  
}  
defer resp.Body.Close()  
bodyText, err := io.ReadAll(resp.Body)  
if err != nil {  
log.Fatal(err)  
}  
  
  
var dictResponse DictResponse  
err = json.Unmarshal(bodyText, &dictResponse)  
if err != nil {  
log.Fatal(err)  
}  
item := dictResponse.Details[0]  
jsonStr := item.Detail  
  
  
var myData DictResponseData  
err2 := json.Unmarshal([]byte(jsonStr), &myData)  
if err != nil {  
log.Fatal(err2)  
}  
fmt.Println("火山翻译")  
for _, item := range myData.Result[0].Ce.Basic.Explains {  
fmt.Println(item.Text, item.Pos, item.Trans)  
}  
}

参考

工具网站

相关推荐
夭要7夜宵3 天前
Go 垃圾回收 | 豆包MarsCode AI刷题
青训营笔记
末班车4224 天前
前端框架中的设计模式 | 豆包MarsCode AI刷题
青训营笔记
VanceLLF4 天前
神奇数字组合 | 豆包MarsCode AI刷题
青训营笔记
lann4 天前
Go 程序的优化 | 豆包MarsCode AI刷题
青训营笔记
用户52281271049785 天前
性能优化与调试技巧 | 豆包MarsCode AI刷题
青训营笔记
千慌百风定乾坤7 天前
Go 语言入门指南:基础语法和常用特性解析(下) | 豆包MarsCode AI刷题
青训营笔记
FOFO7 天前
青训营笔记 | HTML语义化的案例分析: 粗略地手绘分析juejin.cn首页 | 豆包MarsCode AI 刷题
青训营笔记
滑滑滑8 天前
后端实践-优化一个已有的 Go 程序提高其性能 | 豆包MarsCode AI刷题
青训营笔记
柠檬柠檬9 天前
Go 语言入门指南:基础语法和常用特性解析 | 豆包MarsCode AI刷题
青训营笔记
用户967136399659 天前
计算最小步长丨豆包MarsCodeAI刷题
青训营笔记