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

75 阅读6分钟

走进 Go 语言基础语言

Go语言是一种开源的编程语言,于2009年由Google公司开发并推出。Go语言旨在提高程序员的生产力,同时具有高效、可靠和简洁等特点。目前,许多知名的公司和项目都在使用Go语言,如谷歌、Uber、Docker、Kubernetes等等。

什么是Go语言

Go语言是一种静态类型、编译型语言,它具有高效、可靠、简单、安全等特点。Go语言的语法简单,容易上手,而且可以在不同的操作系统上编译运行。

哪些公司在使用Go语言

许多知名的公司和项目都在使用Go语言,以下是一些例子:

  • 谷歌:Go语言的创造者就是谷歌的三位工程师之一,目前谷歌内部有大量的Go语言项目。
  • Uber:Uber的后端系统采用了大量的Go语言开发。
  • Docker:Docker的核心组件都是用Go语言编写的。
  • Kubernetes:Kubernetes是一个开源的容器编排引擎,也是用Go语言编写的。
  • 等等

字节跳动为什么全面拥抱Go语言

字节跳动是一家国内知名的互联网公司,旗下有很多知名的应用程序,如今已经成为了全球最有价值的创业公司之一。字节跳动早在2017年就开始推广Go语言,目前已经成为了公司的主要编程语言之一。字节跳动之所以选择Go语言,主要原因有以下几点:

  • 高效:Go语言具有高效的并发性能,可以支持高并发的应用程序。
  • 简洁:Go语言的语法简单、易学、易用,可以帮助开发者提高生产效率。
  • 安全:Go语言有内存安全、类型安全等特性,可以有效地防止代码漏洞和攻击。

入门

开发环境

要学习Go语言,首先需要搭建好开发环境。Go语言的官方网站提供了各种操作系统的安装包,可以到官方网站下载对应的安装包进行安装。同时,也可以使用一些第三方的集成开发环境,如Goland、VSCode等。

基础语法

Go语言的基础语法与其他编程语言类似,包括变量、常量、运算符、流程控制语句等等。以下是一些基础语法的示例:

变量

Go语言中的变量声明需要使用var关键字,如下所示:

var a int = 10
var b, c string = "hello", "world"

可以看出,Go语言中的变量声明需要显式地指定类型。同时,也可以使用短变量声明语法:

x := 10
y, z := "hello", "world"

在使用短变量声明语法时,Go语言会根据变量的值自动推断出变量类型。

常量

Go语言中的常量声明需要使用const关键字,如下所示:

const pi float32 = 3.14
const (
    apple = "red"
    banana = "yellow"
)

常量的值在程序运行期间是不可修改的。

运算符

Go语言中支持各种常见的运算符,包括算术运算符、比较运算符、逻辑运算符等等。以下是一些常用的运算符示例:

a, b := 10, 20
c := a + b
d := a > b
e := true && false

流程控制语句

Go语言中的流程控制语句包括if语句、for语句、switch语句等等。以下是一些常用的流程控制语句示例:

if a > b {
    fmt.Println("a is greater than b")
} else {
    fmt.Println("a is less than or equal to b")
}

for i := 0; i < 10; i++ {
    fmt.Println(i)
}

switch x {
case 1:
    fmt.Println("x is 1")
case 2:
    fmt.Println("x is 2")
default:
    fmt.Println("x is not 1 or 2")
}

实战

猜数字游戏

猜数字游戏是一个简单的控制台游戏,玩家需要猜测一个随机数,直到猜对为止。以下是一个使用Go语言编写的猜数字游戏示例:

package main

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

func main() {
	rand.Seed(time.Now().UnixNano())
	target := rand.Intn(100) + 1
	fmt.Println("Welcome to the guess the number game!")
	fmt.Println("I'm thinking of a number between 1 and 100. Can you guess what it is?")
	var guess int
	for i := 1; ; i++ {
		fmt.Printf("Guess #%d: ", i)
		fmt.Scan(&guess)
		if guess == target {
			fmt.Printf("Congratulations, you guessed it in %d tries!\n", i)
			break
		} else if guess < target {
			fmt.Println("Too low. Try again.")
		} else {
			fmt.Println("Too high. Try again.")
		}
	}
}

命令行词典

命令行词典是一个基于控制台的小型词典程序,可以通过命令行输入单词查询其翻译。以下是一个使用Go语言编写的命令行词典示例:

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
)

type Translation struct {
	Translation []string `json:"translation"`
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: dict <word>")
		return
	}
	word := strings.Join(os.Args[1:], " ")
	resp, err := http.Get("http://fanyi.youdao.com/translate?&doctype=json&type=AUTO&i=" + url.QueryEscape(word))
	if err != nil {
		fmt.Println(err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	var data struct {
		ErrorCode int          `json:"errorCode"`
		Translate []*Translation `json:"translateResult"`
	}
	err = json.Unmarshal(body, &data)
	if err != nil {
		fmt.Println(err)
		return
	}
	if data.ErrorCode != 0 {
		fmt.Printf("Failed to translate: error code %d\n", data.ErrorCode)
		return
	}
	fmt.Printf("%s: %s\n", word, data.Translate[0].Translation[0])
}

socks5代理

socks5代理是一种常见的代理服务器协议,可以实现TCP和UDP流量的转发,常用于加速访问、隐藏真实IP等。以下是一个使用Go语言编写的socks5代理示例:

package main

import (
	"fmt"
	"io"
	"log"
	"net"
)

func handleConn(conn net.Conn) {
	defer conn.Close()
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err != nil {
		log.Println(err)
		return
	}
	if buf[0] != 0x05 {
		log.Println("Invalid SOCKS version:", buf[0])
		return
	}
	n, err = conn.Write([]byte{0x05, 0x00})
	if err != nil {
		log.Println(err)
		return
	}
	n, err = conn.Read(buf)
	if err != nil {
		log.Println(err)
		return
	}
	if n < 10 || buf[1] != 0x01 {
		log.Println("Invalid SOCKS5 request:", buf[:n])
		return
	}
	addrType := buf[3]
	var dest string
	switch addrType {
	case 0x01:
		dest = net.IPv4(buf[4], buf[5], buf[6], buf[7]).String()
	case 0x03:
		dest = string(buf[5 : n-2])
	case 0x04:
		dest = net.IP(buf[4:8]).String()
	default:
		log.Println("Unknown address type:", addrType)
		return
	}
	port := fmt.Sprintf("%d", (int(buf[n-2]) << 8) | int(buf[n-1]))
	targetAddr := net.JoinHostPort(dest, port)
	log.Println("Connecting to", targetAddr)
	target, err := net.Dial("tcp", targetAddr)
	if err != nil {
		log.Println(err)
		return
	}
	defer target.Close()
	_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
	if err != nil {
		log.Println(err)
		return
	}
	go io.Copy(target, conn)
	io.Copy(conn, target)
}

func main() {
	listener, err := net.Listen("tcp", "127.0.0.1:1080")
	if err != nil {
		log.Fatal(err)
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
			continue
		}
		go handleConn(conn)
	}
}

该示例中,程序首先监听本地1080端口,等待客户端连接。一旦有客户端连接,就向客户端发送0x05 0x00表示支持socks5协议,并等待客户端发送请求。

客户端请求的格式为:[VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT],其中:

  • VER:协议版本,这里应该是0x05;
  • CMD:命令,0x01表示CONNECT;
  • RSV:保留字段,0x00;
  • ATYP:地址类型,0x01表示IPv4地址,0x03表示域名,0x04表示IPv6地址;
  • DST.ADDR:目标地址;
  • DST.PORT:目标端口。

程序首先检查协议版本,然后向客户端发送0x05 0x00表示支持无需认证的连接。然后解析请求,获取目标地址和端口,并建立连接。最后在新建协程中将客户端和目标服务器的连接转发即可。

总结

本篇学习笔记主要介绍了Go语言的基础语法和几个简单的实战项目,包括猜数字游戏、命令行词典和socks5代理。其中,猜数字游戏主要介绍了Go语言的基本语法、控制流和函数;命令行词典主要介绍了Go语言的网络编程和JSON解析;socks5代理则介绍了Go语言的并发编程和网络编程。

总的来说,Go语言具有简洁的语法、高效的编译速度和良好的并发性能,是一门非常适合编写网络应用和系统工具的语言。对于想要学习Go语言的读者来说,可以从语法基础开始学习,并结合实际项目来加深理解。