go 语言入门以及小实践

63 阅读3分钟

go 语言基础语法与小实践

仓库链接:wangkechun/go-by-example

  • 第一部分主要为了解go语言的一些基本语法,在这里就不多赘述,各种样例在仓库的 example 文件夹中。

    这里指路一个适合基础语法入门的教程网站 Go 语言教程 | 菜鸟教程

  • 第二部分为三个小实践

    1. 猜数字游戏
    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
    	}
    }
    
    • rand.Seed() 方法在目前的最新版本中已经被废弃,现在只要使用**math/rand** 中 rand.Intn() 或者其它的随机数方法,其默认会为你设置随机数种子

    • 这里使用的是 bufioos.Stdin 来读取命令行输入,bufio 提供一个 reader 接口,但是使用了缓存机制,在一次性读取大量数据时会有更好的性能,这里是为了第3个小实践做铺垫。

    • 由于 reader 读取的时候会读取所有的输入,所以自然包含了行末的换行符,这里通过**strings.Trim()** 方法来去除换行符,然后通过 strconv.Atoi() 将读取的字符串转换成整形最后进行比较

    1. 词典翻译

      代码太多了,就不放出来,自行前往仓库查看

    • 这个小项目主要讲述如何通过浏览器的debug功能来捕获一些翻译网站的http请求,然后通过模拟这些请求来实现我们想要的功能

    • 其中可以使用一些代码生成工具来快速生成代码,而不需要我们自己根据请求来一个一个手打。

    • curl2go: 将从浏览器复制的curl命令转为go语言代码,自行在浏览器搜索一个可用的网站即可。这里提供一个:curl-to-Go: Convert curl commands to Go code

    • json2struct: 将从浏览器中获取的响应json转换为结构体,以方便获取之后进行json解析,自行在浏览器搜索一个可用的网站即可。这里提供一个:在线JSON转Golang Struct - JSON中文网

    1. socks5代理

      代码太多了,就不放出来,自行前往仓库查看

    • 这里需要我们去了解一下socks5协议的原理和细节 SOCKS5 协议原理详解与应用场景分析 - chris599 - 博客园

    • 在有了基本的了解之后,其本质就是将两个tcp管道通过一个中间人连接在一起,而socks5服务端就是这个中间人,核心代码:

      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)
      _, 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
      

      其中也可以将 context.WithCancel() 替换为 sync.WaitGroup 来实现两个 goroutine 的同步