Go语言上手-基础语言01 | 青训营笔记

66 阅读5分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

Go语言上手-基础语言

1 Go语言的特点

  • 高性能、高并发
  • 语法简单、学习曲线平缓
  • 丰富的标准库
  • 完善的工具链
  • 静态链接
  • 快速编译
  • 跨平台
  • 垃圾回收

2 Go语言基础语法

变量

Go语言是强类型语言,变量需要显式声明;
变量声明方式一
var 变量名 类型 = 值

var b,c int = 1,2

声明后没初始化的变量,会自动初始化为零值(0,"",false,nil) 变量声明方式二
变量名 := 值

a := 20

省略了变量类型,通过 := 完成声明和赋值
:只能用在函数体内,不能用于全局变量声明和赋值,且局部变量需要被使用

常量

常量是在程序运行时,不会被修改的量。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

const b,c = 20,"abc"

可以省略类型

if else

if后面的条件不用加圆括号,但if语句的后面要接花括号

if 7%2 == 0 {
        fmt.Println("7 is even")
    } else {
        fmt.Println("7 is odd")
    }

条件语句之前也可以加声明语句,声明的变量可以在语句的所有条件分支中使用

if num := 9; num < 0 {
        fmt.Println(num, "is negative")
    } else if num < 10 {
        fmt.Println(num, "has 1 digit")
    } else {
        fmt.Println(num, "has multiple digits")
    }

Go中没有三目运算符

for循环

for是Go中唯一的循环结构。

  • 单个循环条件(while)
for i <= 3 {
        fmt.Println(i)
        i = i + 1
    }
  • 初始/条件/后续
for j := 7; j <= 9; j++ {
        fmt.Println(j)
    }
  • 不带条件的for循环等于 for true,遇到break或者return才会停
for {
        fmt.Println("loop")
        break
    }
  • 支持continue

switch循环

  • switch后面的变量不用加小括号,也可以不带表达式,替代if else语句;
  • case的表达式也可以不用常量;
  • default也是可选的;
  • 每个case后不用加break(区别于Java),不会继续跑其他case;
t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("It's before noon")
    default:
        fmt.Println("It's after noon")
    }

数组

数组声明

var a [5]int
b := [5]int{1, 2, 3, 4, 5}

fmt.Println 打印数组时,会按照 [v1 v2 v3 ...] 的格式打印 数组长度固定,开发中较少使用

切片slice

定义切片

var identifier []type //声明一个未指定大小的数组来定义切片
var slice1 []type = make([]type, len) //make函数来声明
slice1 := make([]type, len) // := 语法省略var
make([]T, length, capacity) // make时还可以指定容量

切片的函数

append函数
向slice追加元素,可能返回一个新的slice

s := make([]string, 3)
s = append(s, "d")
s = append(s, "e", "f")
  • 还可以slice[low:high]来切片,slice[:]等同于复制;
  • copy(slice1,slice2)复制slice1到slice2;
  • slice也可以组成多维数据结构,内部的slice长度可以不一致;
  • fmt.Println打印slice和数组类似;

map

创建一个空 map,需要使用内建函数 makemake(map[key-type]val-type)
使用 name[key] = val 语法来设置键值对

m := make(map[string]int)
m["k1"] = 7
m["k2"] = 13

函数 len 可以返回一个 map 的键值对数量;
函数 delete 可以从一个 map 中移除键值对; 取值时用_, prs = map[key]可以查询map中是否包含指定key(包含的话prs为true,否则为true,防止不存在key和key对应的value为0,都会输出0的歧义)

range

  • range在数组和 slice 中提供对每项的索引和值的访问,不需要索引时可以用_来忽略
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
    sum += num
}
  • range在map中迭代键值对,也可以只遍历map的键;
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {         
    fmt.Printf("%s -> %s\n", k, v)     
}                                                                      ```
for k := range kvs {    
    fmt.Println("key:", k)     
}

函数

  • 定义的返回值类型在函数名后面
  • 可以有多返回值,用_灵活选择
  • 可变参数,可以接收任意数量的同类型参数,
func sum(nums ...int) {
    fmt.Print(nums, " ")
    total := 0
    for _, num := range nums {
        total += num
    }
    fmt.Println(total)
}

func main() {

    sum(1, 2)
    sum(1, 2, 3)

    nums := []int{1, 2, 3, 4}
    sum(nums...)
}

指针

指针变量指向了一个值的内存地址;
指针声明

var var_name *var-type = &variable
  • &变量:表示变量的存储地址,即指针;
  • *指针:表示指针对应的值; 函数调用时,基本数据是值传递,不会修改实参,可以通过指针进行传参,来修改实参

结构体

结构体中我们可以为不同项定义不同的数据类型。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体的定义

type Books struct {\
   title string\
   author string\
   subject string\
   book_id int\
}

访问结构体成员

结构体.成员名

结构体方法

func (变量名 结构体名) 方法名 (参数列表) 返回值类型 {}

结构体位置可以带指针(操作结构体),也可以不带

接口interface

定义接口

type geometry interface {
    area() float64
    perim() float64
}

结构体如果实现了接口中的所有抽象方法,就属于实现了该接口。 实现了该接口后,就可以调用接口中的方法。

错误处理

函数的返回值类型里加error,如果error为nil,就说明没有返回错误;

字符串操作

标准库的strings
字符串格式化

JSON处理

  • 结构体的属性名字段首字母大写,就可以被其他包访问(类似于public)
  • 同样可以通过json.Marshal来序列化,会变成buf数组(可以理解为字符串,默认是16进制编码),string(buf)类型转化后就可以打印字符串;
  • 字符串可以通过json.unMarshal来反序列化到一个空变量;

时间处理

time.Now()
time.Date()构造带时区的时间
Format格式,常用"2006-01-02 15:04:05"
now.Unix()可以获取时间戳

数字解析

字符串和数字的转换,都在strconv包下

进程信息

os.Args可以获取进程在执行时的命令行参数
os.Getenv 获取环境变量 os.Setenv 设置环境变量

3 猜谜游戏(实战项目1)

package main

import (
   "bufio"
   "fmt"
   "math/rand"
   "os"
   "strconv"
   "strings"
   "time"
)

func main() {
   maxNum := 100
   // 用时间戳随机初始化种子
   rand.Seed(time.Now().UnixNano())
   // 生成随机数(0-100)
   secretNum := rand.Intn(maxNum)
   // fmt.Println("The secret number is ", secretNum)

   fmt.Println("Please input your guess")
   // 通过os.Stdin来读,用bufio.NewReader来转换为只读的流
   reader := bufio.NewReader(os.Stdin)
   for {
      // 用ReadString来读取一行输入
      input, err := reader.ReadString('\n')
      if err != nil {
         fmt.Println("An error occurred while reading input. Please try again", err)
         continue
      }
      // 去掉换行和回车
      input = strings.TrimSuffix(input, "\r\n")
      // 字符串转换为数字
      guess, err := strconv.Atoi(input)
      if err != nil {
         fmt.Println("Invalid input. Please input an integer value")
         continue
      }
      fmt.Println("Your guess is ", guess)
      if guess > secretNum {
         fmt.Println("Your guess is bigger. Please try again")
      } else if guess < secretNum {
         fmt.Println("Your guess is smaller. Please try again")
      } else {
         fmt.Println("Correct, you Legend")
         break
      }
   }

}

4 在线词典(实战项目2)

package main

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

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"`
}

type DictRequest struct {
   Transtype string `json:"trans_type"`
   Source    string `json:"source"`
   UserId    string `json:"user_id"`
}

func query(word string) {
   // 创建http的client
   client := &http.Client{}

   request := DictRequest{Transtype: "en2zh", Source: word}
   buf, err := json.Marshal(request)
   if err != nil {
      log.Fatal(err)
   }
   // 创建http的post请求,data是一个流
   var data = bytes.NewReader(buf)
   req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
   // 设置请求头
   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.127 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)
   }
   // 访问的body是一个流,用defer来关闭流,函数结束后从下往上触发
   defer resp.Body.Close()
   // 用ioutil把流读到内存里,变成字节数组
   bodyText, err := ioutil.ReadAll(resp.Body)
   if err != nil {
      log.Fatal(err)
   }

   // 防止resp的状态不是200,比如说是404等,加入检验代码可以方便排查问题
   if resp.StatusCode != 200 {
      log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
   }

   // 打印的是json字符串
   // fmt.Printf("%s\n", bodyText)
   var dictResponse DictResponse
   err = json.Unmarshal(bodyText, &dictResponse)
   if err != nil {
      log.Fatal(err)
   }
   // 打印详细信息
   // fmt.Printf("%#v\n", dictResponse)
   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)
}