走进Go语言的语言基础|青训营笔记

42 阅读8分钟

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

前言

本人小白,专科软件技术大二,欢迎大家欢迎大家批评与指正

Go语言的基本介绍

Go语言是一门:静态强类型、编译并发型语言,也是区块链最主流的编程语言。
公式:Go = C+Python{拥有静态运行速度,动态快速开发}

1. 基本功能介绍

  • (1)Go语言从C语言中继承了很多理念,包括表达式语法、控制结构、基础数据类型、调用参数传值、指针等等,也保留了和C语言一样的编译执行方式及弱化的指针
  • (2) 引入包的概念,用于组织程序结构,Go语言的一个文件都要归属于一个包,而不能单独存在。
  • (3) 垃圾回收机制。内存自动回收,不需要开发人员管理,防止造成内存泄露
  • (4) 天然并发性能。从语言层面支持并发,实现简单
  • (5) 吸收了管道通信机制。形成Go语言特有的管道channel。通过管道channel可以实现不同的goroute之间的相互通信
  • (6) 函数可以返回多个值
  • (7) 新的创新比如切片(slice)、延时执行defer等

2.吉祥物:【金花鼠】

金花鼠.jpg

Go语言的快速入门&课程代码剖析

1、变量&introduce

Go语言主要有四种类型的声明语句:var、const、type和func,分别对应变量、常量、类型和函数实体对象的声明。

变量的两种声明方式

一般类型:“var 变量名字 类型 = 表达式”//自己定义变量类型

简短变量声明:“名字 := 表达式”//自动推导类型

不给变量赋值时,接口或引用类型(包括slice、指针、map、chan和函数)变量对应的零值是nil
简短变量声明被广泛用于大部分的局部变量的声明和初始化。var形式的声明语句往往是用于需要显式指定变量类型的地方,或者因为变量稍后会被重新赋值而初始值无关紧要的地方。

1.1变量&Code

`/* 变量 */
var a = "Hiro"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e) // 创建变量并赋值
g := a + "llj"
fmt.Println(a, b, c, d, e, f, g)

/* 匿名变量 */
_, v, _ := getData()
fmt.Println("匿名变量", v)

/* 常量 */
const s string = "constant"
const h = 500000000
const i = 3e20 / h
ft.Println(s, h, i, math.Sin(h), math.Sin(i))`

未定义类型可自动识别,定义了数据类型未赋值编译不报错,编译器给定默认初始值

2、指针&introduce

2.1指针&Code

func add(n int) {
	n += 2
}
func addPtr(n *int) {
	*n += 2
}
func main() {
	x := 5
	add(x)
	fmt.Println(x) //5
	addPtr(&x)
	fmt.Println(x) //7
}

两个函数一个接收的参数是基本类型,一个是指针类型,两个函数对变量n进行相同操作,但是输出的值却不同?
解释:因为形参(n int)接收的是x的地址值,x地址值里存放的是5,函数内n取到的是n存放的地址值的值”5“,*n += 2其实改变的是x地址存放的值,所以结果输出7 如图:

解释指针.jpg

3、系列(range)

Go语言可以使用for range遍历数组、切片、字符串、map及通道(channel)

数组、切片、字符串返回索引和值。
map 返回键和值。
通道(channel)只返回通道内的值。
遍历数组、切片——获得索引和元素

3.1系列(range)&Code

nums := []int{2, 3, 4}
	sum := 0
	for i, num := range nums {
		sum += num
		if num == 2 {
			fmt.Println("index:", i, "num:", num)
		}
	}
	fmt.Println(sum)//index: 0 num: 2

	m := map[string]string{"a": "A", "b": "B"}
	for k, v := range m {
		fmt.Println(k, v)
	}
	for k := range m {
		fmt.Println("key", k)
	}

定义一个nums切片里面存了值"2,3,4";i为数组下标,num为数组下标对应的值,当num==2时输出index和num
map类型可以写为map[K]V,其中K和V分别对应key和value的数据类型”{}“输入的是键值对;两种遍历第一种显示key和value;第二种只输出value

4、数组&Slice

切片:

Golang中的切片,不是拷贝,而是定义了新的指针,指向了原来数组所在的内存空间所以,修改了切片数组的值,也就相应的修改了原数组的值了

  • 切片并不存储任何数据,它只是描述了底层数组中的一段。
  • 更改切片的元素会修改其底层数组中对应的元素。
  • 与它共享底层数组的切片都会观测到这些修改。

4.1数组&Code

	/* 数组声明 */
	str := [4]string{
		"aaa", "bbb", "ccc", "ddd",
	}
	fmt.Println(str)

	/* 数组切片·[上界:下界) */
	a := str[0:2]
	b := str[1:3]
	fmt.Println(a, b) //aaabbb bbbccc

	b[0] = "XXX"      //取某一片段没有分配地址空间
	fmt.Println(a, b) //aaabbb XXXccc
	fmt.Println(str)  //不变还是 aaa XXX ccc ddd

	/* make(数据类型,len,cap) 创建动态数组 */
	num := make([]int, 5) //len(aq) = 5 指定长度
	num[0] = 3
	num[1] = 4
	fmt.Println("len:", len(num))
	num = append(num, 5, 6, 7)
	fmt.Println(num, "len:", len(num))

	fmt.Println(num[2:5])
	fmt.Println(num[2:])
	fmt.Println(num[:5])

	good := []string{"g", "o", "o", "d"}
	fmt.Println(good)

5、集合(Map)&Using

内置的make函数可以创建一个map:

ages := make(map[string]int)

也可以用map字面值的语法创建map,同时还可以指定一些最初的key/value:

ages := map[string]int{
    "alice":   31,
    "charlie": 34,
}
//相当于
ages := make(map[string]int)
ages["alice"] = 31
ages["charlie"] = 34

使用内置的delete函数可以删除元素:

delete(ages, "alice") // remove element ages["alice"]

如果元素类型是一个数字,你可能需要区分一个已经存在的0,和不存在而返回零值的0,可以像下面这样测试:

age, ok := ages["bob"]
if !ok { /* "bob" is not a key in this map; age == 0. */ }

5.1集合(Map)&Code

        /* map */
	m := make(map[string]int) //key:value
	m["one"] = 1
	m["two"] = 2
	fmt.Println(m)//map[one:1 two:2]
	fmt.Println(len(m))//2
	fmt.Println(m["one"])//1
	fmt.Println(m["unknow"])//0
        //判断key是否存在
	r, ok := m["unknow"]
	fmt.Println(r, ok)//0 false

	delete(m, "one")

	m2 := map[string]int{"one": 1, "two": 2}
	var m3 = map[string]int{"one": 1, "two": 2}
	fmt.Println(m2, m3)//map[one:1 two:2] map[one:1 two:2]

  1. 使用内置的make函数创建一个map,对map指定两组key:value,打印输出键值对、长度、"one"和"unkonw"的值,"unkonw"不存在则返回0。
  2. 可以使用ok判断"unkonw"是否是存在,存在输出相应的值和true
  3. 删除m中"one"的值
  4. 使用map字面值的语法创建map

6、函数

//方法的定义:
func (recevier type) methodName (参数列表)(返回值列表){
	方法体
	return 返回值
}
//recevier type 结构体或自定义类型

6.1函数&Code

func main() {
	fmt.Println(add(2, 3))
	list := map[string]string{"a": "A", "b": "B"}
	fmt.Println(exists(list, "a")) //判断key "a" 在map中是否存在

}
//计算两个数的和
func add(a, b int) int {
	return a + b
}
//判断map中是否有指定的键值,有的话返回该键值判断为true(否者return 0,false)
func exists(m map[string]string, k string) (v string, ok bool) {
	v, ok = m[k]
	return v, ok
}

7、语句

7.1语句&Code

package main

import (
	"fmt"
	"math"
	"time"
)

func main() {
	fmt.Println(pow(2, 2, 10)) //输出小于v的x^n
	fmt.Println(cycleFor())    //for循环1-100的和
	cycleSwitch()              //switch比较目前时间
	delay()                    //
	fmt.Println(add(13, 14))   //13+14
	a, b := swap("Hello", "World")
	fmt.Println(a + b)

}

/* if语句 */
func pow(x, n, lim float64) int { //返回值类型
	if v := math.Pow(x, n); v < lim {
		return int(v) //强制类型转换int()
	}
	return int(lim)
}

/* 循环语句 */
func cycleFor() int {
	sum := 1
	for sum <= 100 {
		sum += sum
	}
	return sum
}

/* switch语句 */
func cycleSwitch() {
	t := time.Now() //显示目前的时间
	fmt.Println(t)
	switch {
	case t.Hour() < 12:
		fmt.Println("It's before noon")
	default:
		fmt.Println("It's after noon")
	}
}

/*
	defer语句:

将函数推迟到外层函数返回之后执行(从下向上执行)
语句后面必须是函数调用语句
*/
func delay() {
	defer fmt.Println("World")
	fmt.Println("Hello")
}

/* 函数(使用小写的函数,是private的,使用大写的函数,是public的) */
func add(a, b int) int {
	return a + b
}

/* 函数·多返回值*/
func swap(x, y string) (string, string) {
	return x, y
}

8、结构体

结构体变量的成员可以通过点操作符访问:
结构体名称.变量名(user.name)

8.1结构体&Code

package main

import "fmt"

type user struct {
	name     string
	password string
}

//检查传递的密码是否和储存在结构体中的密码相同
func (u user) checkPassword(password string) bool {
	return u.password == password
}
func (u *user) restPassword(password string) {
	u.password = password
}
func main() {
	a := user{name: "wang", password: "1024"}
	a.restPassword("2048") //更改密码
	fmt.Println(a.checkPassword("2048"))
}

创建结构体定义变量指定类型,

Go语言的环境搭建

CSDN教程有很多输入关键词”使用VSCODE配置GO语言开发环境“即可

  • pkgm 创建主函数
  • for for语句
  • forr for-range表达式 [集合、数组、切片、string、map]
  • ff printf输出
  • fp println输出

  • git clone “ssh路径”//克隆文件到本地
  • go mod init ”项目名“//生成mod文件[相当于项目模块]
  • go build “文件名” //生成.exe文件
  • ./main.exe //运行exe文件

  • go test //开始测试
  • go test -v //显示详细信息测试
  • ctrl c //终端强制退出 再安装相应插件即可

插件.jpg

Go语言项目实战

1、在线字典(Online dictionary)

1.1项目解析: 打开云彩小译在线翻译,右键检查——输入一个单词(good)——点击NetWork——点击Fetch/XHR——找到dict——右键Copy——点击Copy as URL(bash)——将拷贝内容复制到curl command中复制转化内容运行到编译器中,将输出结果拷贝到点击转换—嵌套得到结构体,再按如下Code操作

package main

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

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() {
	var word string
	fmt.Println("请输入你要查询的单词:")
	fmt.Scanln(&word)
	client := &http.Client{}
	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("authority", "api.interpreter.caiyunai.com")
	req.Header.Set("accept", "application/json, text/plain, */*")
	req.Header.Set("accept-language", "zh-CN,zh;q=0.9")
	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", "Google Chrome";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")
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
	// 发起请求
	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)
	}
	if resp.StatusCode != 200 {
		log.Fatal("bad StatusCode", resp.StatusCode, "body", string(bodyText))
	}
	var dictResponse DictResponse
	err = json.Unmarshal(bodyText, &dictResponse)
	if err != nil {
		log.Fatal(err)
	}
	// 最详细的结果打印整个结构体
	// fmt.Printf("%#v\n", dictResponse)
	fmt.Println("UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
	for _, item := range dictResponse.Dictionary.Explanations {
		fmt.Println(item)
	}

}