Go语言基础-基础语法|青训营笔记

151 阅读7分钟

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

本堂课重点内容:

  • Go基础语法及几个常用的标准库
  • 实战案例
    1. 猜谜游戏
    2. 在线词典
    3. SOCKS5代理

详细知识点介绍

基础语法

  1. Go变量的定义
```
var (
   a = 1
   b = true
   c = "def"
)//批量定义变量

func variableZeroValue() {
   var a int//使用var关键字定义变量
   var s string
   fmt.Println(a, s)
   //空串不显示,换一种打印方式
   fmt.Printf("%d %q\n", a, s)//0 ""
}

func variableInitialValue() {
   var a, b int = 3, 4
   var s string = "abc"
   fmt.Println(a, b, s)
}

func variableTypeDeduction() {
   var a, b, v, s = 3, 4, true, "def"
   fmt.Println(a, b, v, s)
}

func variableShorter() { //在函数外面不能这样定义变量
   a, b, v, s := 3, 4, true, "def"
   fmt.Println(a, b, v, s)
}

func euler() { //golang内建变量有复数 complex64或者complex128
   fmt.Printf("%.3f\n", cmplx.Pow(math.E, 1i*math.Pi)+1)
}

func triangle() { //golang中没有隐式类型转换,必须强制转换
   var a, b int = 3, 4
   var c int
   c = int(math.Sqrt(float64((a*a + b*b))))
   fmt.Println(c)
}

func consts() { //golang常量的定义
   const (
      fileename = "abc.txt"
      a, b      = 3, 4 //当我们没有规定类型是,在下面的使用时它会根据语句推断为float64
   )

   var c int = int(math.Sqrt(a*a + b*b))
   fmt.Println(c)
}

func enums() { //枚举类型,使用const关键字定义
   const (
      cpp  = 0
      java = 1
   )
   fmt.Println(cpp, java)
   //使用iota,从0开始自加
   const (
      a = 1 << (10 * iota)
      b
      _ //iota仍然会递增一次,只是没有使用
      c
   )
   fmt.Println(a, b, c)
}
```
  1. Go中的循环和分支

Go语言中的分支语句和其他语言差不多,不同的是在if语句中判断的条件不用加括号(Go的语法中相对于其他语言很多地方都将括号省略了),而switch语句相对于其他语言就更为强大了,判断的值可以是任意类型,也可以不写,在case后写上判断条件,并且当一个case匹配后会直接跳出判断,不需要break语句。

```
func grade(score int) string {
   g := ""
   //golang中switch会自动break,除非使用fallthrough
   switch { //switch后面可以没有表达式
   case score < 0 || score > 100:
      g = "wrong score"
   case score < 60:
      g = "不及格"
      //fallthrough
   default:
      g = "及格"
   }
   return g
}
```

Go语言中的循环只有for,如果后面三条语句里面只保留一条就相当于while循环

  1. Go函数定义 与C相比,Go函数的返回值是后置的,并且可以返回多个
```
func div(a, b int) (int, int) {
   return a / b, a % b
} //还可以像下面这样写,但是不推荐
//func div(a, b int) (q,r int) {
//  q=a/b
//  r=a%b
// return
//}

func sum(numbers ...int) int { //可变参数列表
   s := 0
   for i := range numbers {//Go迭代遍历
      s += numbers[i]
   }
   return s
}

func swap(a, b *int) {//没有返回值时直接省略,不需要void
   *a, *b = *b, *a
}
```
  1. 结构体定义
```
type treeNode struct {
   value       int
   left, right *treeNode
}
```
  1. 数组、切片、map Go里面数组用的比较少,大部分时间都是使用切片 数组
```
//注意,数组是值类型,在函数里面操作数组的值,原数组的值不能改变
func main() {
   var arr1 [5]int
   arr2 := [3]int{1, 3, 5} //这样定义要负初值
   arr3 := [...]int{2, 3, 4, 5}
   var grid [4][5]int
   fmt.Println(arr1, arr2, arr3)
   fmt.Println(grid)
   //遍历数组
   for i := 0; i < len(arr3); i++ {
      fmt.Print(arr3[i])
   }
   fmt.Printf("\n")
   //使用range遍历数组
   for i := range arr3 {
      fmt.Print(arr3[i])
   }
   fmt.Printf("\n")
   //同时获得下标和值
   for i, v := range arr3 {
      fmt.Println(i, v)
   }
}
```

切片

```
func main() {
   var s []int //切片不是数组

   for i := 0; i < 100; i++ {
      printSlice(s)
      s = append(s, 2*i+1)
   }
   fmt.Println(s)

   s1 := []int{2, 4, 6, 8} //系统先建立一个长度为4的数组,然后再取一个view
   fmt.Println(s1)
   //当我们知道切片所需要的长度但不知道值时,可以使用make函数
   s2 := make([]int, 16)     //len==cap==16
   s3 := make([]int, 10, 32) //len==10,cap==32
   printSlice(s2)
   printSlice(s3)
   //copy slice
   copy(s2, s1)
   fmt.Println(s2)
   printSlice(s2)
   //删除元素
   s2 = append(s2[:3], s2[4:]...)
   fmt.Println(s2)
   printSlice(s2)
}
```

map

```
func main() {
   m1 := map[string]string{
      "love": "han",
      "1314": "wait",
   }

   var m2 map[string]int      //empty map
   m3 := make(map[string]int) //nil

   fmt.Println(m1, m2, m3)
   fmt.Println("Traversing map")
   for k, v := range m1 {
      fmt.Println(k, v)
   } //打印出来的顺序是不一样的
   fmt.Println("Getting values")
   loveName := m1["love"] //如果我们取得key在map里没有,会返回一个空串
   fmt.Println(loveName)
   //处理map里找不到对应key的方法
   if secondName, ok := m1["1314"]; ok {
      fmt.Println(secondName)
   } else {
      fmt.Println("key does not exist")
   }
   fmt.Println("Deleting values")
   fmt.Println(m1)
   delete(m1, "1314")
   fmt.Println(m1)
}
```

几个常用标准库

json库,主要是marshal和unmarshal方法 time库,和时间相关的一些方法 strconv库,和数字解析相关的一些方法 os/exec库,和进程相关的一些方法

实战案例

猜谜游戏

猜谜游戏其实就是平常玩的数字炸弹游戏

package main

import (
	"fmt"
	"math/rand"
	"os"
	"time"
)

func main() {
	var min, max int = 0, 100
	var t, key int
	rand.Seed(time.Now().UnixNano()) //不做这部处理的话每次随机数都是相同的
	key = rand.Intn(100)
	fmt.Printf("key: %v\n", key)
	for {
		fmt.Println("请输入你猜的数字")
		fmt.Scanf("%d", &t)
		switch {
		case t > key:
			max = t
			fmt.Printf("你猜大了,现在的范围是%d到%d之间\n", min, max)
		case t < key:
			min = t
			fmt.Printf("你猜小了,现在的范围是%d到%d之间\n", min, max)
		default:
			fmt.Println("你猜中了")
			os.Exit(0)
		}
	}
}
在线词典

我们自己向服务器发送请求,然后处理返回的json数据,增加另外一个翻译器支持并使用goroutine并发获取数据。 使用的代码生成工具:[json转struct](在线工具 - OKTools)、[通过curl command生成Go代码](Convert curl to Go (curlconverter.com))

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
)

var wg sync.WaitGroup

type DictRequest struct {
	TransType string `json:"trans_type"`
	Source    string `json:"source"`
}

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"`
		IsSubject string `json:"is_subject"`
		Item      struct {
			Source string `json:"source"`
			Target string `json:"target"`
		} `json:"item"`
		ImageURL string `json:"image_url"`
		Sitelink string `json:"sitelink"`
		ID       string `json:"id"`
	} `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) {
	defer wg.Done()
	client := &http.Client{}
	// var data = strings.NewReader(`{"trans_type":"zh2en","source":"喜欢"}`)
	// word:="love"
	dictRequest := DictRequest{"en2zh", word}
	b, err2 := json.Marshal(dictRequest)
	if err2 != nil {
		fmt.Println("序列化json数据出错")
	}
	data := bytes.NewReader(b)
	req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("authority", "api.interpreter.caiyunai.com")
	req.Header.Set("accept", "application/json, text/plain, */*")
	req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
	req.Header.Set("app-name", "xy")
	req.Header.Set("content-type", "application/json;charset=UTF-8")
	req.Header.Set("device-id", "")
	req.Header.Set("origin", "https://fanyi.caiyunapp.com")
	req.Header.Set("os-type", "web")
	req.Header.Set("os-version", "")
	req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
	req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Microsoft Edge";v="108"`)
	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", "cross-site")
	req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76")
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != 200 {
		fmt.Println("error,返回的StatusCode为", resp.StatusCode)
	}
	defer resp.Body.Close()
	bodyText, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	// fmt.Printf("%s\n", bodyText)
	var dictResponse DictResponse
	err3 := json.Unmarshal(bodyText, &dictResponse) //传地址,否则写入不进去
	if err3 != nil {
		fmt.Println("返回的数据反序列化失败")
	}
	// fmt.Printf("dictResponse: %#v\n", dictResponse)

	fmt.Println("来自彩云小译的结果:")
	fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
	for _, item := range dictResponse.Dictionary.Explanations {
		fmt.Println(item)
	}
}

type DictResponseByBaidu struct {
	TransResult struct {
		Data []struct {
			Dst        string          `json:"dst"`
			PrefixWrap int             `json:"prefixWrap"`
			Result     [][]interface{} `json:"result"`
			Src        string          `json:"src"`
		} `json:"data"`
		From     string `json:"from"`
		Status   int    `json:"status"`
		To       string `json:"to"`
		Type     int    `json:"type"`
		Phonetic []struct {
			SrcStr string `json:"src_str"`
			TrgStr string `json:"trg_str"`
		} `json:"phonetic"`
	} `json:"trans_result"`
	DictResult struct {
		Edict struct {
			Item []struct {
				TrGroup []struct {
					Tr          []string `json:"tr"`
					Example     []string `json:"example"`
					SimilarWord []string `json:"similar_word"`
				} `json:"tr_group"`
				Pos string `json:"pos"`
			} `json:"item"`
			Word string `json:"word"`
		} `json:"edict"`
		Collins struct {
			Entry []struct {
				EntryID string `json:"entry_id"`
				Type    string `json:"type"`
				Value   []struct {
					MeanType []struct {
						InfoType string `json:"info_type"`
						InfoID   string `json:"info_id"`
						Example  []struct {
							ExampleID string `json:"example_id"`
							TtsSize   string `json:"tts_size"`
							Tran      string `json:"tran"`
							Ex        string `json:"ex"`
							TtsMp3    string `json:"tts_mp3"`
						} `json:"example"`
					} `json:"mean_type"`
					Gramarinfo []struct {
						Tran  string `json:"tran"`
						Type  string `json:"type"`
						Label string `json:"label"`
					} `json:"gramarinfo"`
					Tran   string `json:"tran"`
					Def    string `json:"def"`
					MeanID string `json:"mean_id"`
					Posp   []struct {
						Label string `json:"label"`
					} `json:"posp"`
				} `json:"value"`
			} `json:"entry"`
			WordName      string `json:"word_name"`
			Frequence     string `json:"frequence"`
			WordEmphasize string `json:"word_emphasize"`
			WordID        string `json:"word_id"`
		} `json:"collins"`
		From        string `json:"from"`
		SimpleMeans struct {
			WordName  string   `json:"word_name"`
			From      string   `json:"from"`
			WordMeans []string `json:"word_means"`
			Exchange  struct {
				WordThird []string `json:"word_third"`
				WordIng   []string `json:"word_ing"`
				WordDone  []string `json:"word_done"`
				WordPl    []string `json:"word_pl"`
				WordPast  []string `json:"word_past"`
			} `json:"exchange"`
			Tags struct {
				Core  []string `json:"core"`
				Other []string `json:"other"`
			} `json:"tags"`
			Symbols []struct {
				PhEn  string `json:"ph_en"`
				PhAm  string `json:"ph_am"`
				Parts []struct {
					Part  string   `json:"part"`
					Means []string `json:"means"`
				} `json:"parts"`
				PhOther string `json:"ph_other"`
			} `json:"symbols"`
		} `json:"simple_means"`
		Lang   string `json:"lang"`
		Oxford struct {
			Entry []struct {
				Tag  string `json:"tag"`
				Name string `json:"name"`
				Data []struct {
					Tag  string `json:"tag"`
					Data []struct {
						Tag   string `json:"tag"`
						P     string `json:"p"`
						PText string `json:"p_text"`
					} `json:"data"`
				} `json:"data"`
			} `json:"entry"`
			Unbox []struct {
				Tag  string `json:"tag"`
				Type string `json:"type"`
				Name string `json:"name"`
				Data []struct {
					Tag     string   `json:"tag"`
					Text    string   `json:"text,omitempty"`
					Words   []string `json:"words,omitempty"`
					Outdent string   `json:"outdent,omitempty"`
					Data    []struct {
						Tag    string `json:"tag"`
						EnText string `json:"enText"`
						ChText string `json:"chText"`
					} `json:"data,omitempty"`
					EnText string `json:"enText,omitempty"`
					ChText string `json:"chText,omitempty"`
				} `json:"data"`
			} `json:"unbox"`
		} `json:"oxford"`
		Sanyms []struct {
			Tit  string `json:"tit"`
			Data []struct {
				P string   `json:"p"`
				D []string `json:"d"`
			} `json:"data"`
			Type string `json:"type"`
		} `json:"sanyms"`
		Usecase struct {
			Collocation struct {
				Data []struct {
					P  string `json:"p"`
					Ex []struct {
						En string `json:"en"`
						Zh string `json:"zh"`
					} `json:"ex"`
				} `json:"data"`
				Desc string `json:"desc"`
			} `json:"collocation"`
			Idiom []struct {
				P    string `json:"p"`
				Tag  string `json:"tag"`
				Data []struct {
					Tag  string `json:"tag"`
					Data []struct {
						EnText string `json:"enText"`
						Tag    string `json:"tag"`
						ChText string `json:"chText"`
					} `json:"data"`
					Xt string `json:"xt,omitempty"`
				} `json:"data"`
			} `json:"idiom"`
		} `json:"usecase"`
		Synonym []struct {
			Synonyms []struct {
				Tips string `json:"tips"`
				Bx   string `json:"bx"`
				Syn  struct {
					P    string   `json:"p"`
					Word string   `json:"word"`
					D    []string `json:"d"`
				} `json:"syn"`
				Ex []struct {
					EnText string `json:"enText"`
					ChText string `json:"chText"`
				} `json:"ex"`
			} `json:"synonyms"`
			Guide string   `json:"guide"`
			Words []string `json:"words"`
		} `json:"synonym"`
		BaiduPhrase []struct {
			Tit   []string `json:"tit"`
			Trans []string `json:"trans"`
		} `json:"baidu_phrase"`
	} `json:"dict_result"`
	LijuResult struct {
		Double string   `json:"double"`
		Tag    []string `json:"tag"`
		Single string   `json:"single"`
	} `json:"liju_result"`
	Logid int `json:"logid"`
}

func QueryByBaidu(word string) {
	defer wg.Done()
	client := &http.Client{}
	dateReader := `from=en&to=zh&query=` + word + `&transtype=translang&simple_means_flag=3&sign=198772.518981&token=de0de4ea09af4dd20d455ac7aa269fb0&domain=common`
	var data = strings.NewReader(dateReader)
	req, err := http.NewRequest("POST", "https://fanyi.baidu.com/v2transapi?from=en&to=zh", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Accept", "*/*")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
	req.Header.Set("Acs-Token", "1673856314151_1673861704496_5nfnvniCGuXKn17dtB6RTyrRRI9R/oBRE0HDY6EvG3Dj35U1s9t37gbU7Nec5lgZi7FMcCYhoiz/GLHPT27sHyTqHJfDm4im8j1ELWemPJV4/DBlVF1n268/AumjZR56NdVydZuEfB9R9MPkscIvjjz/nULoFwpOAcISbQdAtB248SdcCH/5SxBhdMKLutOuaFVdeIzphWUfqBCxygXWVXhp4uIbCuNtt7D3jO9AqbLFImV/IIx2FSIezb3DN8JwSu5DNPEvxV/nZYh1qo+MCyDZq/grltsahEbZtnwQTa3htOioxeKE4JVvFJE8E+NOCaNTx9IxSDwffKFqIXiMPg==")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
	req.Header.Set("Cookie", "BAIDUID=B55A4DC651D1A0B9042B8F8C23B03416:FG=1; BAIDUID_BFESS=B55A4DC651D1A0B9042B8F8C23B03416:FG=1; APPGUIDE_10_0_2=1; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BIDUPSID=B55A4DC651D1A0B9042B8F8C23B03416; PSTM=1671683094; ZFY=OqJz2n:AhY1EfwdFdC:AAZIUJMbGurE9NH2EG35hwu:Ac8:C; __bid_n=185482736aee8ad5b34207; FEID=v10-5a44b605f95016ea3af95dd6eb86a68f1d4feeb9; __xaf_fpstarttimer__=1672130803245; __xaf_thstime__=1672130804655; __xaf_fptokentimer__=1672130804658; FPTOKEN=QCBDwd99wGK387CJ2fEAMjKUu2B6Jl0WRh/cs9QEkDo4D0L+y8jJEdeqnzehedtRafrHuDfkC8m+/zWpAFBa9xxP5ZySpQGQ1lKS3RF9ivTY/y7QA9zb8rrGPgH9loSkX8cWJbf5u0K33yhsQ1wbI6OM8q8RUoIOsIVBEIbktQ08iD8YrJpVPBTLMmriQGpcdBVguL0TA6g9yU9Fc8+e2KE3pMQ1RKvQBWyAZsb8G301fxTlLJEDjUaEVapDGv/iipIToiei6i1oMpgmWOzR01cJccJPPsWp9bHa8xNUFeexHqSS0NI6S1LivykqBmIlB/f9aJ4FV7umPq2J48WwgRWk2CCD+Q+Esc+iFVE8LWTqBQvbp2B215zFIrxbcDbNGwUm4d3UMcgM8WfocVUDOw==|L+ur0ygOSzGV1UuicuyBy6h7GNMTEUtcZseLBYemJPg=|10|64a2c0498b99d62da72900a80389bcdc; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1672659396,1672719233,1673067930,1673861578; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1673861578; ab_sr=1.0.1_MmU2M2Q1ODJhYzhhYzFhOTdmN2FjMWZiNGVjZGRkNDQyNzMwN2E1ZDkwYzkwOGZmM2ZlMzJiYTNhYzMwMDFhYzhiNGY5ODRlYmVlNjBhYzE3YjBkOTQ5YmE0Y2ZjOWE1ODJmOTEwZTc2NDhmYjY5ZWJjMGExYzA1YTQ4OTIxYjgzOTk1Y2Y5YjE2NTc1NGFmMzM2OTk1ODdhZDUxNzBmYQ==")
	req.Header.Set("Origin", "https://fanyi.baidu.com")
	req.Header.Set("Referer", "https://fanyi.baidu.com/")
	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/108.0.0.0 Safari/537.36 Edg/108.0.1462.76")
	req.Header.Set("X-Requested-With", "XMLHttpRequest")
	req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Microsoft Edge";v="108"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("sec-ch-ua-platform", `"Windows"`)
	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)
	}
	// fmt.Printf("%s\n", bodyText)
	var dictResponseByBaidu DictResponseByBaidu
	err2 := json.Unmarshal(bodyText, &dictResponseByBaidu)
	if err2 != nil {
		fmt.Println("返回的数据反序列化失败")
	}
	// fmt.Printf("dictResponse: %#v\n", dictResponseByBaidu)
	fmt.Println("来自百度翻译的结果:")
	for _, item := range dictResponseByBaidu.DictResult.SimpleMeans.WordMeans {
		fmt.Println(item)
	}
}
func main() {
	if len(os.Args) != 2 {
		fmt.Println("请传入需要查询的单词")
		os.Exit(1)
	}
	wg.Add(2)
	var word string = os.Args[1]
	go Query(word)
	go QueryByBaidu(word)
	wg.Wait() //等待执行完成再退出程序
}

SOCKS5代理

由于这个练习背后涉及的知识和代码较复杂,这篇文章篇幅也已经较长了,所以会在后面重新写一篇文章来记录。