go语言入门 | 青训营笔记

108 阅读4分钟

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

1.1 go语言安装

Downloads - The Go Programming Language 网址下载go的安装包

image.png 无脑安装

1.2 ide goland 安装

在goland官网找到2021.3.4版本的开发环境,下载并安装

image.png

安装好之后 可以在链接GoLand 激活方法 2022版 最新简易教程 (52shizhan.cn)中获取激活码,然后使用插件进行激活,最后我的ide的激活日期如下图所示:

image.png 已经激活到5000年

1.3 环境配置

在goland文件夹中新建goworkStation文件夹,并在此文件夹下新建如下文件夹,

image.png 其中bin中存放编译安装程序目录,pkg中存放依赖,src中为项目源码

在系统环境变量中,添加goroot、gopath目录,并将其添加至path目录中,如下图所示

image.png

image.png

在命令行窗口查看安装的go版本 image.png

image.png 此时环境配置成功

2 简介

Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。

Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 ,Go语言是一个非常现代化的语言,精小但非常强大。

Go 语言最主要的特性:

  • **自动垃圾回收
  • **更丰富的内置类型
  • **函数多返回值
  • **错误处理
  • **匿名函数和闭包
  • **类型和接口
  • **并发编程
  • **反射
  • **语言交互性

2.1 第一个demo

在goland中新建go文件,然后将以下代码输入编译、运行

package main

import "fmt"

func main() {//左大括号必须和函数名同一行,否则报错
   fmt.Println("hello,world")//分号可加可不加
}

结果

image.png

2.2 变量和常量(iota)

package main

import (
   "fmt"
   "math"
)

func main() {
   //局部声明变量方式1
   var a int
   fmt.Println("a=", a)
   //声明变量方式2
   var b int = 100
   fmt.Println("b=", b)
   //声明变量方式3
   var c = 200
   fmt.Println("c=", c)
   fmt.Printf("c=%v,type of c=%T\n", c, c)
   //声明变量方式4(常用)
   e := 300
   fmt.Printf("e=%v,type of e=%T\n", e, e)
   f := float64(e)
   fmt.Printf("f=%f,type of f=%T\n", f, f)

   //常量
   const eh = 2000
   const i = eh / 4
   fmt.Println(eh, math.Sin(i))
    //多个变量
    var ll, yy = 123, "sad"
    fmt.Println(ll, yy)
}

全局变量没有第四种方式

iota:自增,仅可以在const中使用,默认值为0

const (
   u1 = iota * 10 //iota=0
   u2             //iota=1,u2=10
   u3             //iota=2,u3=20
)
fmt.Println(u1, u2, u3)

image.png

2.3 流程控制语句

go语言中的if else和C+类似。不同点是条件没有(),如是写的话,那么在保存的候编译器会合自动去掉。第二个不同点是后面必须跟大活号

if num := 9; num < 0 {
   fmt.Println("是负数")
} else {
   fmt.Println("不是负数哦")
}

switch语句 1、go中的switch语句和C++比较类似,区别是switch后面的那个变量名不加括号 2、除此之外,在执行一个case之后,在C++中如果不加break语句,则程序会一直执行结束,直到遇到break为止,但在go中是不需要加break的 3、go中的switch语句可以使用任意的变量类型,甚至可以取代if else语句,例如可以在switch语句中不加变量然后在case中写逻辑,可以使代码更清晰

//switch
grade := "A"
switch {
case grade == "A":
   fmt.Printf("优秀!\n")
case grade == "B", grade == "C":
   fmt.Printf("良好\n")
case grade == "D":
   fmt.Printf("及格\n")
case grade == "F":
   fmt.Printf("不及格\n")
default:
   fmt.Printf("差\n")
}

2.4 循环

在go中只有一种循环,即for循环,最简单的循环就是一个for+{} 代表死循环,可以使用continue和break来跳出或者继续

qq := -5
for qq <= 0 {
   fmt.Println(qq)
   qq++
}

//for {
// time.Sleep(5 * time.Second)
//}
for i := 0; i < 5; i++ {
   fmt.Println("我爱学go")
}
//结果
-5                            
-4                            
-3                            
-2                            
-1                            
0                             
我爱学go                      
我爱学go                      
我爱学go                      
我爱学go                      
我爱学go                      

2.5 数组

在真实的业务里面很少使用数组,通常使用切片 数组的语法如下

//数组
//var variable_name [SIZE] variable_type
var balance [10]float32 //数组长度不确定可以使用[]
balance[0] = 1

//初始化数组
var balance1 = []float32{1000.0, 2.0, 3.4, 7.0, 50.0}
//或者
balance2 := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
fmt.Println(len(balance1))
//可以指定具体位置的元素
balance3 := [5]float32{1: 2.0, 3: 7.0}
balance1[0] = 4
balance2[0] = 4
balance3[0] = 4
var twoD [2][3]int
twoD[0][0] = 1

2.6 切片

Go 语言切片是对数组的抽象。

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。 slice的初始化

//定义方式1
var identifier []type
//定义方式2
slice1 := make([]type, len)

//slice
slice1 := make([]int, 3)
slice1[0] = 0
slice1[1] = 1
fmt.Println(len(slice1))
slice1 = append(slice1, 12)
fmt.Println(slice1)

qw := make([]int, 3)
copy(qw, slice1[:3]) //此处不包括3位置的元素
fmt.Println(qw)

2.7 map

map是实际过程中使用最多的数据结构,golang中的map是无序的,遍历的时候也不会按照顺序,他的顺序是随机的。

//map
var map1 = make(map[string]int)
map1["one"] = 1
map1["two"] = 2
fmt.Println(map1)
fmt.Println(len(map1))

r, ok := map1["three"]
fmt.Println(r, ok)
delete(map1, "one")
fmt.Println(map1)

2.8 range

我们可以使用range来快速遍历map和slice,在遍历的时候回返回两个值,第一个是索引,第二个是对应的值,如果不需要用索引的话,可以使用下划线忽略

//range
nums := []int{1, 2}
sum := 0
for i, num := range nums {
   sum += num
   fmt.Printf("sum is %d,index is %d", sum, i)
}

map2 := make(map[string]int)
map2["ss"] = 8
for k, v := range map2 {
   fmt.Println(k, v)
}

2.9 函数

go和其他的语言的不同之处在于,他的变量类型是后置的,并且可以返回多个值,在真实的业务中也是返回两个,第一个是真正的返回结果,第二个是错误信息

    //函数
   map3 := make(map[string]int)
   map3["sa"] = 1
   v, ok := exists(map3, "sa")
   fmt.Println(v, ok)
}
func exists(m map[string]int, k string) (v int, ok bool) {
   v, ok = m[k]
   return v, ok
}

2.10 指针

go中的指针支持的操作有限,一个重要的用途是对于传入的参数进行修改,和C++中使用方法差不多 如下代码所示

n := 1
   add1(&n)
   fmt.Println(n)
}
func add(a int) {
   a = a + 2
}

func add1(a *int) {
   *a = *a + 2
}

2.11 结构体

    //结构体

   struct1 := user{"ccc", "1234"}
   struct2 := user{}
   struct2.name = "sdksd"
   fmt.Println(struct1)
   fmt.Println(checkPassword(struct1, "1234"))
}

type user struct {
   name     string
   password string
}

func checkPassword(u user, password string) bool {
   return u.password == password
}
func checkPassword1(u *user, password string) bool {
   return u.password == password
}

类似于C中的结构体,不多赘述

2.11.1 结构体方法

image.png

//结构体方法

   res := struct2.checkPassword("1234")
   fmt.Println(res)
}

type user struct {
   name     string
   password string
}

func (u user) checkPassword(password string) bool {
   return u.password == password
}

可以为结构体定义方法,类似于其他语言中的类成员函数,只需要在函数头开头()放入结构体即可,如上图所示

2.12 错误处理

错误处理在go中的做法是使用单独的返回值来传递错误信息,go中没有异常,在函数实现的时候,return需要返回两个值,如果出现错误的话,可以返回nil和error,如果正确的话则返回原本的结果和nil

//错误处理
   user1 := []user{{"cc", "123"}}
   u, err := findUser(user1, "cc")
   if err != nil {
      fmt.Println(err)
      return
   }
   fmt.Println(u.name)
}
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")
}

2.13 字符串操作

//字符串处理
str := "hello1"
str1 := "hello2"
strr := []string{str, str1}
fmt.Println(strings.Contains(str, "ll"))
fmt.Println(strings.Count(str1, "l"))
fmt.Println(strings.Index(str, "l"))
fmt.Println(strings.Join(strr, "-"))
fmt.Println(strings.Replace(str, "he", "hh", -1))
fmt.Println(strings.ToUpper(str))

格式化输出 常用的两种 println和printf 前者类似于java中的标准输出 后者类似于c语言中的输出

//格式化输出
n1 := 123
p := point{1, 2}
fmt.Println(n1, p)

fmt.Printf("s=%v\n", str)
fmt.Printf("s=%v\n", p)

2.14 json操作

一个现有的结构体需要转化为json时,只需要将结构体的每一个成员首字母大写(即让其变为公开字段)即可使用 json.Marshal 方法对其进行序列化。同时我们也可以对一个序列化后的字符串使用 json.Unmarshal 进行反序列化。在输出时要使用 string 类型转换,否则将输出为十六进制数字。如果不想要输出的字段名为大写,可以给字段后加加一个 tag 或者说是别名。

image.png

    //json
   aa := userInfo{"wang", 23, []string{"love", "ll"}}
   buf, err := json.Marshal(aa)
   if err != nil {
      panic(err)
   }
   fmt.Println(buf)
   fmt.Println(string(buf))
   //buf, err = json.MarshalIndent(aa, "", "\t")
   var bb userInfo
   err = json.Unmarshal(buf, &bb)
   if err != nil {
      panic(err)
   }
   fmt.Printf("序列化结果%v", bb)
}

2.15 时间处理

//时间处理
now := time.Now()
fmt.Println(now) //2023-01-16 20:02:02.7679312 +0800 CST m=+0.00582790
//使用time.date构造时间
t := time.Date(2023, 1, 16, 1, 25, 60, 0, time.UTC)
t1 := time.Date(2024, 1, 16, 1, 25, 60, 0, time.UTC)
fmt.Println(t)
diff := t1.Sub(t)
fmt.Println(diff)

fmt.Println(now.Format("2006-01-02 15:04:05"))
//获取时间戳
fmt.Println(now.Unix())

2.16 数字解析

//数字解析
f, _ = strconv.ParseFloat("1.23456", 64)
fmt.Println(f)
n12, _ := strconv.ParseInt("11", 10, 64)
fmt.Println(n12)
nn, _ := strconv.Atoi("123456")
fmt.Println(nn)

可以用strconv包下的函数进行转换,是string convert的缩写 可以用parseInt或者parseFloat 解析字符串,也可以用Atoi把字符串转化为数字,或者itoA把数字转化为字符串

3 案例

猜数字

package main

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

func main() {
   maxNum := 100
   rand.Seed(time.Now().UnixNano())
   secretNumber := rand.Intn(maxNum)

   fmt.Println("请输入你的数字:")
   var input string
   //reader := bufio.NewReader(os.Stdin)
   for {
      //input, err := reader.ReadString('\n')
      //if err != nil {
      // fmt.Println("输入发生错误", err)
      // return
      //}
      //input = strings.TrimSuffix(input, "\r\n")
      //fmt.Printf("%#v", input)

      //fmt.Scanf("%s", &input)
      fmt.Scanf("%s\n", &input)
      fmt.Printf("%#v", input)
      guess, err := strconv.Atoi(input)
      if err != nil {
         fmt.Println("转换出错")
      }
      fmt.Println("your guess: ", guess)
      if guess > secretNumber {
         fmt.Println("大了")
      } else if guess < secretNumber {
         fmt.Println("小了")
      } else {
         fmt.Println("对了")
         break
      }
   }
}

遇到几个问题 使用scanf在输入时,循环会执行两次,查阅资料后发现是因为输入的换行符也会被处理,因此需要在%s加\n,可以使用scan或者scanln更方便 可以看这个博客 blog.51cto.com/u_14454410/…

在线词典

在火狐浏览器请求,可以看到参数和响应

image.png image.png 然后使用curl工具将其转化为go的格式 链接如下 Convert curl to Go (curlconverter.com)

将json转化为结构体 在线工具 - OKTools

package main

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

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

func query(word string) {
   client := &http.Client{}

   request := DictRequest{TransType: "en2zh", Source: word}
   buf, err := json.Marshal(request)
   data := bytes.NewReader(buf)
   //将字符串转化为流
   //var data = strings.NewReader(`{"trans_type":"en2zh","source":word}`)
   //创建请求
   req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
   if err != nil {
      log.Fatal(err)
   }
   //添加请求头
   req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0")
   req.Header.Set("Accept", "application/json, text/plain, */*")
   req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
   // req.Header.Set("Accept-Encoding", "gzip, deflate, br")
   req.Header.Set("Content-Type", "application/json;charset=utf-8")
   req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
   req.Header.Set("app-name", "xy")
   req.Header.Set("version", "1.8.0")
   req.Header.Set("os-type", "web")
   req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
   req.Header.Set("Connection", "keep-alive")
   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("TE", "trailers")
   //发起请求
   resp, err := client.Do(req)
   if err != nil {
      log.Fatal(err)
   }
   //body是流,避免资源泄漏,defer会在函数执行完之后去执行
   defer resp.Body.Close()
   bodyText, err := ioutil.ReadAll(resp.Body)
   if err != nil {
      log.Fatal(err)
   }
   //fmt.Printf("%s\n", bodyText)

   var bodyResp AutoGenerated
   err = json.Unmarshal(bodyText, &bodyResp)
   if err != nil {
      log.Fatal(err)
   }
   fmt.Println(bodyResp.Dictionary.Explanations)
}

type AutoGenerated 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() {
   var word string
   count, err := fmt.Scanln(&word)
   if err != nil {
      fmt.Println(err, count)

   }
   query(word)
}

可以使用在线翻译_翻译在线__英语翻译_英文翻译_日语翻译__fanyi_爱词霸 (iciba.com)