#青训营第一天学习笔记
##go语言基础语法
###array and slice
####array
import "fmt"
func main() {
a := [5]int{1, 2, 3, 4, 5}
a[4] = 100
fmt.Println(a[4], len(a))
fmt.Println(a)
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
//造多维的数据结构
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
}
####slice
import "fmt"
func main() {
//slice是一个可变长度的数组
s := make([]string, 3) //创建slice
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println(len(s))
s = append(s, "d") //尾部增加一个
s = append(s, "e", "f") //尾部增加多个
fmt.Println(s)
c := make([]string, len(s))
copy(c, s) //copy slice
fmt.Println(c)
fmt.Println(c[2:5]) //输出c[2],c[3],c[4]
fmt.Println(c[:5])
fmt.Println(c[2:])
}
###const
import "fmt"
func main() {
const length int = 100 //只读操作,不可修改
fmt.Println(length)
//const定义枚举类型
const (
beijing = iota //iota初始默认为0,逐行加一
shanghai
shenzhen
)
const (
a, b = iota + 1, iota + 2
c, d
e, f = iota * 2, iota * 3
g, h
)
fmt.Println()
}
###error handing
import (
"errors"
"fmt"
)
func f1(art int) (int, error) {
if arg == 42 {
return -1, errors.New("can't work with 42")
}
return arg + 3, nil //返回值为nil表示没有错
}
type argError struct {
arg int
prob string
}
func (e *argError) Error() string { //结构体方法
return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
func f2(arg int) (int, error) {
if arg == 42 {
return -1, &argError{arg, "can't work with it"}
}
return arg + 3, nil
}
func main() {
for _, i := range []int{7, 42} {
if r, e := f1(i); e != nil {
fmt.Println("f1 failed:", e)
} else {
fmt.Println("f1 worked:"
}
}
for _, i := range []int{7, 42} {
if r, e := f2(i); e != nil {
fmt.Println("f2 failed:", e)
} else {
fmt.Println("f2 worked:")
}
}
_, e := f2(42)
if ae, ok := e.(*argError); ok {
fmt.Println(ae.arg)
fmt.Println(ae.prob)
}
}
###for
func main() {
var j int = 1
for {
} //死循环
for i := 1; i <= 10; i++ {
//可用continue和break
} //c循环
for j <= 3 {
j++
} //一般循环
}
###function
import "fmt"
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return
}
// 指针
func add2(n *int) {
*n += 2
}
// 可变参数函数
func sum(nums ...int) {
fmt.Print(nums, " ") //将Println结尾本该打印出的换行符换成" "打印
fmt.Println(nums)
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
// 闭包
func intSeq() func() int { //intSeq函数返回另一个在intSeq函数体中定义的匿名函数
i := 0
return func() int { //fuc()这个匿名函数使用闭包的方式隐藏变量i
i += 1
return i
}
}
func main() {
n := 1
add2(&n)
sum(1, 2)
nextInt := intSeq()
fmt.Println(nextInt()) //1
fmt.Println(nextInt()) //2.更新i的值
fmt.Println(nextInt()) //3
newInts := intSeq()
fmt.Println(newInts()) //1
}
###if else
import "fmt"
func main() {
if 8%4 == 0 {
fmt.Println("abcdef")
}
}
###JSON
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int `json:"age"` //声明对应的json key
Hobby []string
} //保证公开字段大写开头,就可以用json。Marshal()进行序列化
func main() {
a := userInfo{Name: "geng", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
buf, err := json.Marshal(a) //将结构体a序列化后的buf,buf是十六进制的编码数组,可当成是字符串
if err != nil {
panic(err) //终止当前正在运行的程序
}
fmt.Println(buf) //十六进制
fmt.Println(string(buf)) //强转为字符串类型
//{"Name":"geng","age":18,"Hobby":["Golang","TypeScript"]}
var b userInfo
err = json.Unmarshal(buf, &b) //反序列化给一个结构体类型空变量
}
###map
import "fmt"
func main() {
m := make(map[string]int) //使用make创建一个map
m["k1"] = 7 //加入一对映射
m["k2"] = 13
fmt.Println("map:", m)
v1 := m["k1"]
fmt.Println("v1: ", v1)
fmt.Println("len:", len(m))
delete(m, "k2") //删除k2表示的键值对
fmt.Println("map:", m)
_, prs := m["k2"] //_接受可能的值(这个值用不到,用_可避免报错),prs接受true或false,true表示k2可对应的值存在,flase表示不存在
fmt.Println("prs:", prs)
n := map[string]int{"foo": 1, "bar": 2} //创建并初始化map的另一种方式
fmt.Println("map:", n)
}
###range
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums { //range第一个返回值是索引,第二个是值
sum += num
}
fmt.Println("sum:", sum)
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
for k, v := range "go" { //range遍历字符串
fmt.Println(k, v) //直接输出v,是对应的rune编码
fmt.Printf("%d : %q\n", k, v) //用%q输出的是对应的字符
}
}
}
###string
import (
"fmt"
"strings"
)
func main() {
a := "hello"
fmt.Println(strings.Contains(a, "ll")) //true
fmt.Println(strings.Count(a, "l")) //2
fmt.Println(strings.HasPrefix(a, "he")) //true,查找前缀
fmt.Println(strings.HasSuffix(a, "llo")) //trur,查找是否含有这样的后缀
fmt.Println(strings.Index(a, "ll")) //2,查找子序列第一个字符的位置
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) //he-llo
fmt.Println(strings.Repeat(a, 2)) //hellohello,复制加长
fmt.Println(strings.Replace(a, "e", "E", -1)) //n为指定替换个数,若n<0,则替换全部
fmt.Println(strings.Split("a-b-c", "-")) //以-为分界线拆分字符串
fmt.Println(strings.ToLower(a)) //hello,全部转换为小写
fmt.Println(strings.ToUpper(a)) //HELLO
fmt.Println(len(a)) //5,注意:一个汉字占三个字符
}
###format
import "fmt"
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n)
fmt.Println(p) //{1,2}
fmt.Printf("s=%v\n", s) //在使用Printf进行格式化打印时,可以用%v来表示所有类型的变量
fmt.Printf("n=%v\n", n)
fmt.Printf("p=%v", p)
fmt.Printf("p=%+v", p) //详细打印
fmt.Printf("p=%#v", p) //更详细打印
f := 3.1415926
fmt.Println(f)
fmt.Printf("%.2f", f) //3.14
}
###struct
import "fmt"
type person struct {
name string
password string
}
func main() {
//结构体变量的四种初始化方式
a := person{name: "geng", password: "1024"}
b := person{"geng", "1024"}
c := person{name: "geng"}
c.password = "1024"
var d person
d.name = "geng"
d.password = "1024"
fmt.Println(a, b, c, d)
fmt.Println(checkpassword(&a, "hahaha"))
//结构体方法
a.resetpassword("1024")
fmt.Println(a.checkpassword2("1024")) //true
}
func checkpassword(a *person, password string) bool {
return a.password == password
}
// 类成员函数,结构体方法
func (u person) checkpassword2(password string) bool {
return u.password == password
}
func (u *person) resetpassword(password string) { //无返回值
u.password = password //记住要对形参进行修改的话用指针
}
###switch
import (
"fmt"
"time"
)
func main() {
var a int
switch a { //a的类型是任意的
case 1:
fmt.Println("adg") //无需break,执行完case1后直接跳出switch
case 2, 3:
fmt.Println("adg")
default:
}
t := time.Now()
//替换掉多重ifelse
switch {
case t.Hour() < 12: //在每个case里去写条件分支即可
}
}
###time
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now)
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t)
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
fmt.Println(t.Format("2006-01-02 15:04:05"))
diff := t2.Sub(t) //时间段
fmt.Println(diff)
fmt.Println(diff.Minutes(), diff.Seconds()) //进制转换输出
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) //true
fmt.Println(now.Unix()) //时间戳,是自1970年1月1日(08:00:00GMT)至当前时间的总毫秒数。
}
###数字解析
package main
//rtoa
import (
"fmt"
"strconv"
)
func main() {
f, _ := strconv.ParseFloat("1.234", 64) //字符串转64位十进制的浮点数
fmt.Println(f)
n, _ := strconv.ParseInt("111", 10, 64) //64位十进制整数
fmt.Println(n)
n1, _ := strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n1)
n2, _ := strconv.Atoi("123") //十进制数字字符串转换为十进制整数
fmt.Println(n2)
n2, err := strconv.Atoi("AAA") //AAA不是数字字符串,n2=0
fmt.Println(n2, err)
}
##go语言实战案例
###案例一:随机数游戏
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
// fmt.Println("The secret number is ", secretNumber)
fmt.Println("Please input your guess")
reader := bufio.NewReader(os.Stdin)
for {
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)
continue
}
input = strings.Trim(input, "\r\n")
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid input. Please enter an integer value")
continue
}
fmt.Println("You guess is", guess)
if guess > secretNumber {
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("Correct, you Legend!")
break
}
}
}
###案例二:字典查找
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 query(word string) {
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("Connection", "keep-alive")
req.Header.Set("DNT", "1")
req.Header.Set("os-version", "")
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36")
req.Header.Set("app-name", "xy")
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("device-id", "")
req.Header.Set("os-type", "web")
req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
req.Header.Set("Sec-Fetch-Site", "cross-site")
req.Header.Set("Sec-Fetch-Mode", "cors")
req.Header.Set("Sec-Fetch-Dest", "empty")
req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")
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))
}
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)
}
}
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)
}
###案例三:SOCKS5代理
import (
"bufio"
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"log"
"net"
)
const socks5Ver = 0x05
const cmdBind = 0x01
const atypeIPV4 = 0x01
const atypeHOST = 0x03
const atypeIPV6 = 0x04
func main() {
server, err := net.Listen("tcp", "127.0.0.1:1080")
if err != nil {
panic(err)
}
for {
client, err := server.Accept()
if err != nil {
log.Printf("Accept failed %v", err)
continue
}
go process(client)
}
}
func process(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
err := auth(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
err = connect(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
}
func auth(reader *bufio.Reader, conn net.Conn) (err error) {
// +----+----------+----------+
// |VER | NMETHODS | METHODS |
// +----+----------+----------+
// | 1 | 1 | 1 to 255 |
// +----+----------+----------+
// VER: 协议版本,socks5为0x05
// NMETHODS: 支持认证的方法数量
// METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:
// X’00’ NO AUTHENTICATION REQUIRED
// X’02’ USERNAME/PASSWORD
ver, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read ver failed:%w", err)
}
if ver != socks5Ver {
return fmt.Errorf("not supported ver:%v", ver)
}
methodSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read methodSize failed:%w", err)
}
method := make([]byte, methodSize)
_, err = io.ReadFull(reader, method)
if err != nil {
return fmt.Errorf("read method failed:%w", err)
}
// +----+--------+
// |VER | METHOD |
// +----+--------+
// | 1 | 1 |
// +----+--------+
_, err = conn.Write([]byte{socks5Ver, 0x00})
if err != nil {
return fmt.Errorf("write failed:%w", err)
}
return nil
}
func connect(reader *bufio.Reader, conn net.Conn) (err error) {
// +----+-----+-------+------+----------+----------+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
// VER 版本号,socks5的值为0x05
// CMD 0x01表示CONNECT请求
// RSV 保留字段,值为0x00
// ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。
// 0x01表示IPv4地址,DST.ADDR为4个字节
// 0x03表示域名,DST.ADDR是一个可变长度的域名
// DST.ADDR 一个可变长度的值
// DST.PORT 目标端口,固定2个字节
buf := make([]byte, 4)
_, err = io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("read header failed:%w", err)
}
ver, cmd, atyp := buf[0], buf[1], buf[3]
if ver != socks5Ver {
return fmt.Errorf("not supported ver:%v", ver)
}
if cmd != cmdBind {
return fmt.Errorf("not supported cmd:%v", cmd)
}
addr := ""
switch atyp {
case atypeIPV4:
_, err = io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("read atyp failed:%w", err)
}
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
case atypeHOST:
hostSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read hostSize failed:%w", err)
}
host := make([]byte, hostSize)
_, err = io.ReadFull(reader, host)
if err != nil {
return fmt.Errorf("read host failed:%w", err)
}
addr = string(host)
case atypeIPV6:
return errors.New("IPv6: no supported yet")
default:
return errors.New("invalid atyp")
}
_, err = io.ReadFull(reader, buf[:2])
if err != nil {
return fmt.Errorf("read port failed:%w", err)
}
port := binary.BigEndian.Uint16(buf[:2])
dest, err := net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port))
if err != nil {
return fmt.Errorf("dial dst failed:%w", err)
}
defer dest.Close()
log.Println("dial", addr, port)
// +----+-----+-------+------+----------+----------+
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
// +----+-----+-------+------+----------+----------+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
// +----+-----+-------+------+----------+----------+
// VER socks版本,这里为0x05
// REP Relay field,内容取值如下 X’00’ succeeded
// RSV 保留字段
// ATYPE 地址类型
// BND.ADDR 服务绑定的地址
// BND.PORT 服务绑定的端口DST.PORT
_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
if err != nil {
return fmt.Errorf("write failed: %w", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
_, _ = io.Copy(dest, reader)
cancel()
}()
go func() {
_, _ = io.Copy(conn, dest)
cancel()
}()
<-ctx.Done()
return nil
}