这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记
在得知自己通过笔试后,自己便开始提前学习了一会go语言,以便于自己在开营后能跟上学习进度。所以本篇笔记中代码部分均来自于我自己在观看学习了这个b站视频后www.bilibili.com/video/BV1gf…
自己所写的代码。
GO语言的简单配置
go语言的环境变量的配置,和其他语言相差不大。
主要是配置GOROOT,GOPATH这两个变量
GOROOT
GOROOT就是go语言在你电脑上安装的根目录
我们直接在系统变量里新建一个环境变量即可
GOPATH
GOPATH相对于是go语言的工作区,在GOPATH下必须包含 pkg, bin, src等文件夹。当我们使用gopath模式创建项目时,必须将源码保存到src文件夹下。(不过现在开发一般推荐GOModule形式) 同样的我们新建一个系统变量和用户变量,将GOPATH目录配置完成即可。
简单的hello world实例
package main //程序的包名
import(
"fmt"
)
//main函数
func main() { //花括号不换行
fmt.Printf("hello world!!!") //可以加分号,建议不加
}
可以使用go run 运行 main.go文件 使用go build 编译文件 然后使用./main运行
基础语法
变量和常量
Golang中变量声明方式有多种
var a int //不初始化默认为0
var a int = 1
var a = 1
a := 1
-------------
//golang常量没有确定的类型可以通过上下文推断类型
//常量 只读
const length int = 180
//const 可以定义枚举类型
const (
// 可以在const()添加一个关键字iota,每行的iota都会累加1,第一行的iota的默认值为0
BEIJING = 10 * iota
SHANGHAI
ZHIJIANG
)
常用方法
if else
和c/c++,java的区别在于没有括号
if a != nil{
}
for
//死循环
for {
}
for i := 0; i < n; i ++ {
}
i := 1
for i <= 3 {
i ++
}
switch
除开不用加break,其他同c/c++一致
a := 1
switch a{
case 1:
fmt.Println("1")
default:
fmt.Println("x")
}
t := 1
switch a{
//可以使用布尔语句
case t < 12:
fmt.Println("1")
default:
fmt.Println("x")
}
数组和slice
数组
固定容量
//固定长度的数组
var myArray1 [10] int
slice
声明
//声明slice1是切片,初始长度为3, 默认值为1, 2, 3
slice1 := []int{1, 2, 3}
fmt.Printf("len = %d, slice1 = %v\n", len(slice1), slice1)
//声明slice2是一个切片,但是没有给slice2分配空间
var slice2 []int
slice2 = make([]int, 3) //开辟三个空间,默认值为0
fmt.Printf("len = %d, slice2 = %v\n", len(slice2), slice2)
slice3 := make([]int, 3) //通过:=推导出来为切片
fmt.Printf("len = %d, slice1 = %v\n", len(slice3), slice3)
var slice4 []int
if slice4 == nil{
fmt.Println("为空")
}else{
fmt.Println("不为空")
}
追加
package main
import "fmt"
func main(){
var numbers = make([]int, 3, 5)
//向numbers切片追加一个元素1, number len = 4, [0,0,0,1], cap = 5
numbers = append(numbers, 1)
fmt.Printf("len = %d, cap = %d\n", len(numbers), cap(numbers))
//向numbers切片追加一个元素1, number len = 4, [0,0,0,1], cap = 5
numbers = append(numbers, 2)
fmt.Printf("len = %d, cap = %d\n", len(numbers), cap(numbers))
//向cap已满的切片中加入一个新元素,新的cap = 2 * 旧的cap
numbers = append(numbers, 3)
fmt.Printf("len = %d, cap = %d\n", len(numbers), cap(numbers))
fmt.Printf("-----------------\n")
//不规定cap,默认和len相等
var n1 = make([]int, 3)
fmt.Printf("len = %d, cap = %d\n", len(n1), cap(n1))
n1 = append(n1, 1)
fmt.Printf("len = %d, cap = %d\n", len(n1), cap(n1))
}
截取
切片默认执行的是一块内存空间,即s1 = s2[1:] 修改s1,s2也会改变
package main
import "fmt"
func main() {
/* 创建切片 */
numbers := []int{0,1,2,3,4,5,6,7,8}
printSlice(numbers)
/* 打印原始切片 */
fmt.Println("numbers ==", numbers)
/* 打印子切片从索引1(包含) 到索引4(不包含)*/
fmt.Println("numbers[1:4] ==", numbers[1:4])
/* 默认下限为 0*/
fmt.Println("numbers[:3] ==", numbers[:3])
/* 默认上限为 len(s)*/
fmt.Println("numbers[4:] ==", numbers[4:])
numbers1 := make([]int,0,5)
printSlice(numbers1)
/* 打印子切片从索引 0(包含) 到索引 2(不包含) */
number2 := numbers[:2]
printSlice(number2)
/* 打印子切片从索引 2(包含) 到索引 5(不包含) */
number3 := numbers[2:5]
printSlice(number3)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
copy
package main
import "fmt"
func main(){
s := []int{1,2,3}
//copy可以将底层数组的slice一起进行拷贝
s2 := make([]int, 3)
copy(s2, s)
s2[0] = 3
fmt.Println(s[0])
}
slice本质是指向s头的指针,所以copy后修改copy后的切片会修改原切片
Map
Map的四种声明方式
package main
import "fmt"
func main(){
//===>第一种声明方式
//声明myMap1是一种map类型 key是string, value是string
var myMap1 map[string]string
if (myMap1 == nil){
fmt.Println("myMap1是一个空map")
}
//使用map前使用make分配数据空间
myMap1 = make(map[string]string, 10)
myMap1["one"] = "java"
myMap1["two"] = "c++"
myMap1["three"] = "python"
fmt.Println("myMap1 = ", myMap1)
//===>第二种声明方式
myMap2 := make(map[int]string)
myMap2[1] = "java"
myMap2[2] = "c++"
myMap2[3] = "python"
fmt.Println(myMap2)
//===>第三种声明方式
myMap3 := map[string]string{
"one" : "php",
"two" : "c++",
"three" : "python",
}
fmt.Println(myMap3)
}
Map的使用
package main
import "fmt"
func printMap(cityMap map[string]string){
//引用传递
//遍历
for key, value := range cityMap{
fmt.Println("key = ", key, "value = ", value)
}
}
func main(){
cityMap := make(map[string]string)
//添加
cityMap["China"] = "Beijing"
cityMap["Japan"] = "Tokyo"
cityMap["USA"] = "NewYork"
//遍历
printMap(cityMap)
//删除
delete(cityMap, "Japan")
//遍历
printMap(cityMap)
//修改
cityMap["USA"] = "DC"
//遍历
printMap(cityMap)
}
函数
Golang中的函数支持返回多个值,并且返回类型后置,这是和其他语言有明显差别的地方
package main
import "fmt"
func foo1(a string, b int) int {
fmt.Println(a)
fmt.Println(b)
c := 100
return c
}
func foo2() (int, int) {
return 888, 999
}
func foo3() (r1 int, r2 int) {
//r1 r2属于foo3的形参 初始默认值为0
//r1 r2作用域空间 是foo3 整个函数体内部的空间
r1 = 1000
r2 = 2000
return
}
func foo4() (r1, r2 int){
r1 = 1
r2 = 2
return
}
func main(){
a := foo1("ava", 520)
fmt.Println(a)
b, c := foo2()
fmt.Println(b ,c)
e, f := foo3()
fmt.Println(e, f)
g, h := foo4()
fmt.Println(g, h)
}
指针
Golang中的指针并不像c/c++中的那样的复杂
主要掌握,* 和 & 的用法 即可,其中的参数中的值传递和引用传递和其他语言相差不多。
package main
import "fmt"
//值传递
func swap(a int, b int){
var temp int
a = b
b = temp
}
//引用传递
func swap1(a *int, b *int){
var temp int
temp = *a
*a = *b
*b = temp
}
func main(){
var a int = 10
var b int = 20
swap1(&a, &b)
fmt.Println(a, b)
var p *int
p = &a
fmt.Println(p)
fmt.Println(&a)
//指针的指针
var pp **int
pp = &p
fmt.Println(&p)
fmt.Println(pp)
}
结构体
Golang中我们可以为结构体实现一些结构体方法,这类似于Java中的类方法。我们也可以将strut近似的看为一个“类”
结构体的基本创建和使用
package main
import "fmt"
type myint int
type Book struct {
id int
name string
}
func printBook(book Book){
//值传递
fmt.Printf("book = %d, name = %v\n", book.id, book.name)
}
func printBook1(book *Book){
//引用传递
book.id = 2
fmt.Printf("book = %d, name = %v\n", book.id, book.name)
}
func main(){
var a myint = 10
fmt.Println("a = ", a)
var book1 Book
book1.id = 1
book1.name = "xxx"
printBook(book1)
printBook1(&book1)
}
错误处理
Golang中没有异常的存在,Golang中所有的运行报错都是错误。 我们可以直接在方法的返回值中返回一个err,让我们能够直接使用if进行错误的捕获。
结构体标签TAG
我们可以使用结构体标签来对结构进行标记,设定一些信息,比如定义其转换成json时对应的名称
package main
import (
"fmt"
"reflect"
)
type resume struct {
Name string `info:"name" doc:"我的名字" json:"name"`
Sex string `info:"sex" json:"sex"`
}
func findTag(str interface{}){
t := reflect.TypeOf(str).Elem()
for i := 0; i < t.NumField(); i ++ {
tagInfo := t.Field(i).Tag.Get("info")
tagDoc := t.Field(i).Tag.Get("doc")
fmt.Println("info = ", tagInfo)
fmt.Println("doc = ", tagDoc)
}
}
func main() {
var re resume
findTag(&re)
}
实战小栗子🌰
猜数字游戏
功能分析:
- 需要获到一个0~100的一个随机数
- 获取用户输入的数
- 比较并判断结果
- 相同则游戏结束
- 不同则给出提示 并循环
我自己增加了一个简单的扩展,限制玩家的猜测次数 代码本身没什么难点,主要是使用bufio包进行读入比较繁琐
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
//生成随机数
maxNum := 100
//最多猜测次数
maxCnt := 10
//设置随机数种子
rand.Seed(time.Now().UnixNano())
//获取随机数
ansNum := rand.Intn(maxNum)
//需要重置随机数种子否则结果一直为相同的随机数
//fmt.Println("ansNum = ", ansNum)
//简单的扩展:增加一个玩家猜测次数和限制玩家猜测次数
cnt := 0
//循环游戏
for cnt < maxCnt{
cnt ++
//读入数字
fmt.Println("Please input your guess:")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
if err != nil{
fmt.Println("err! Please try again!", err)
return
}
input = strings.TrimSuffix(input, "\n")
guess, err := strconv.Atoi(input)
if err != nil{
fmt.Println("err! Please try again!", err)
return
}
fmt.Println("You guess is", guess)
if guess > ansNum {
fmt.Println("Your guess is bigger than ansNum. Please try again")
}else if guess < ansNum {
fmt.Println("Your guess is smaller than ansNum. Please try again")
}else {
fmt.Println("Correct, you legend, your guess the number is ", cnt)
break
}
}
}
命令行字典
彩云翻译 fanyi.caiyunapp.com/ 进去以后我们随便输入一个单词,翻译,按F12打开开发者工具,选择网络找到dict请求(类型为POST) 复制一下请求包的信息
复制到下面的网站,自动生成代码 curlconverter curlconverter.com/#go
解析response body 代码生成 oktools.net/json2go
代码有一点点长
项目的难点主要是使用代码生成器生成代码并使用。
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 main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WROD example: simpleDict hello`)
os.Exit(1)
word := os.Args[1]
//word := "hello"
query(word)
}
}
func query(word string){
client := &http.Client{}
//创建请求
//自定义data
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("Accept", "application/json, text/plain, */*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
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/100.0.4896.75 Safari/537.36")
req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
req.Header.Set("app-name", "xy")
req.Header.Set("os-type", "web")
req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"`)
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)
}
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
//解析response body
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)
}
}