• Golang第一章:入门


    Golang概述

    Golang学习方向

    区块链研发工程师、Go服务器端/游戏软件工程师、Golang分布式/云计算软件工程师

    Golang应用领域

    • 区块链
    • 后端服务器应用
      • 美团后台流量支撑程序
      • 仙侠道
    • 云计算/云服务后台应用
      • 盛大云CDN
      • 京东信息推送云服务/京东分布式文件系统

    Golang安装

    参考链接

    Golang练习

    HelloWorld

    新建一个文件夹ch1,创建文件helloworld.go

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println("hello world")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    cmd运行 go run helloworld.go 或者 go build helloworld.go生成helloworld.exe,然后运行exe亦可

    其中main包用来定义一个独立的可执行程序,而不是库;同时main函数是程序开始执行的地方

    命令行参数

    echo1.go

    在ch1下创建文件echo1.go

    package main
    
    //导入多个包可以选择用()标识列表,gofmt工具会按字母顺序进行排序
    import (
    	"fmt"
    	"os"
    )
    
    func main() {
    	//默认string变量是空字符串""
    	var s, sep string
    	//这里的Args代表的是从命令行获取的参数列表,i从1开始是因为Args[0]是命令本身的名字
    	for i := 1; i < len(os.Args); i++ {
    		s += sep + os.Args[i]
    		sep = " "
    	}
    	fmt.Println(s)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在cmd输入go run echo1.go 参数1 参数2 参数...
    输出结果为:参数1 参数2 参数...

    echo2.go

    第二种形式的for循环

    package main
    
    import (
    	"fmt"
    	"os"
    )
    
    func main() {
    	s, sep := "", ""
    	//使用range遍历Args会产生两个值:索引和索引对应元素;因为不需要索引,所以我们可以使用空标识符_来占位
    	for _, arg := range os.Args[1:] {
    		s += sep + arg
    		sep = " "
    	}
    	fmt.Println(s)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    echo3.go

    因为前两种s += sep + arg的过程是不断创建新的string变量,不断进行垃圾回收,为了提高效率,我们可以使用工具类strings的Join函数

    package main
    
    import (
    	"fmt"
    	"os"
    	"strings"
    )
    
    func main() {
    	fmt.Println(strings.Join(os.Args[1:], " "))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    找出重复行

    dup1.go

    控制台输入数据,并找出重复出现的部分

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main() {
    	//利用内置函数make定义一个key为string,value为int的map
    	counts := make(map[string]int)
    	input := bufio.NewScanner(os.Stdin)
    	for input.Scan() {
    		counts[input.Text()]++
    	}
    	//忽略input.Err()中可能的错误
    	for line, n := range counts {
    		if n > 1 {
    			fmt.Printf("%d\t%s\n", n, line)
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    命令行ctrl+z回车结束输入

    dup2.go

    可以在标准输入中读取,也可以从具体文件中读取
    流式模式读取输入

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main() {
    	counts := make(map[string]int)
    	files := os.Args[1:]
    	if len(files) == 0 {
    		countLines(os.Stdin, counts)
    	} else {
    		for _, arg := range files {
    			f, err := os.Open(arg)
    			//err等于nil的时候,代表文件正常打开
    			if err != nil {
    				//Fprintf代表在标准错误流上输出一条信息,%v代表使用默认格式显示任意类型的值
    				fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
    				continue
    			}
    			countLines(f, counts)
    			f.Close()
    		}
    	}
    	for line, n := range counts {
    		if n > 1 {
    			fmt.Printf("%d\t%s", n, line)
    		}
    	}
    }
    func countLines(f *os.File, counts map[string]int) {
    	input := bufio.NewScanner(f)
    	for input.Scan() {
    		counts[input.Text()]++
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    dup3.go

    一次读取整个文件输入到大块内存,一次性地分割所有行,然后处理这些行

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    	"os"
    	"strings"
    )
    
    func main() {
    	counts := make(map[string]int)
    	for _, filename := range os.Args[1:] {
    		//data存储的是ReadFile函数返回的可以转化成字符串的字节slice,可以被strings.Split函数分割
    		data, err := ioutil.ReadFile(filename)
    		if err != nil {
    			fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
    			continue
    		}
    		for _, line := range strings.Split(string(data), "\n") {
    			counts[line]++
    		}
    	}
    	for line, n := range counts {
    		if n > 1 {
    			fmt.Printf("%d\t%s\n", n, line)
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    GIF动画

    了解即可

    lissajous.go

    package main
    
    import (
    	"image"
    	"image/color"
    	"image/gif"
    	"io"
    	"log"
    	"math"
    	"math/rand"
    	"net/http"
    	"os"
    	"time"
    )
    
    //定义画板颜色
    var palette = []color.Color{color.White, color.Black}
    
    const (
    	whiteIndex = 0 //画板中的第一种颜色
    	blackIndex = 1 //画板中的下一种颜色
    )
    
    func main() {
    
    	rand.Seed(time.Now().UTC().UnixNano())
    	if len(os.Args) > 1 && os.Args[1] == "web" {
    		handler := func(w http.ResponseWriter, r *http.Request) {
    			lissajous(w)
    		}
    		http.HandleFunc("/", handler)
    		log.Fatal(http.ListenAndServe("localhost:8000", nil))
    		return
    	}
    	lissajous(os.Stdout)
    }
    func lissajous(out io.Writer) {
    	const (
    		cycles  = 5     //完整的x振荡器变化的个数
    		res     = 0.001 //角度分辨率
    		size    = 100   //图像画布包含[-size .. +size]
    		nframes = 64    //动画中的帧数
    		delay   = 8     //以10ms为单位的帧间延迟
    	)
    	freq := rand.Float64() * 3.0 //y振荡器的相对频率
    	anim := gif.GIF{LoopCount: nframes}
    	phase := 0.0 //phase difference
    	for i := 0; i < nframes; i++ {
    		rect := image.Rect(0, 0, 2*size+1, 2*size+1)
    		img := image.NewPaletted(rect, palette)
    		for t := 0.0; t < cycles*2*math.Pi; t += res {
    			x := math.Sin(t)
    			y := math.Sin(t*freq + phase)
    			img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
    		}
    		phase += 0.1
    		anim.Delay = append(anim.Delay, delay)
    		anim.Image = append(anim.Image, img)
    	}
    	gif.EncodeAll(out, &anim) //注意:忽略编码错误
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    cmd输入go build lissajous +lissajous >out.gif可以得到out.gif文件,或者使用go run lissajous >out.gif

    获取一个URL

    fetch.go

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"os"
    )
    
    func main() {
    	for _, url := range os.Args[1:] {
    		resp, err := http.Get(url)
    		if err != nil {
    			fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
    			os.Exit(1)
    		}
    		b, err := ioutil.ReadAll(resp.Body)
    		resp.Body.Close()
    		if err != nil {
    			fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
    			os.Exit(1)
    		}
    		fmt.Printf("%s", b)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    go build fetch.go + fetch http://pop1.io得到请求的页面

    并发获取多个URL

    fetchall.go

    package main
    
    import (
    	"fmt"
    	"io"
    	"io/ioutil"
    	"net/http"
    	"os"
    	"time"
    )
    
    func main() {
    	start := time.Now()
    	//make创建一个string类型的管道
    	ch := make(chan string)
    	for _, url := range os.Args[1:] {
    		go fetch(url, ch) //启动一个goroutine
    	}
    	for range os.Args[1:] {
    		fmt.Println(<-ch) //从通道ch接收
    	}
    	fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
    }
    func fetch(url string, ch chan<- string) {
    	start := time.Now()
    	resp, err := http.Get(url)
    	if err != nil {
    		ch <- fmt.Sprint(err) //发送到通道ch
    		return
    	}
    	nbytes, err := io.Copy(ioutil.Discard, resp.Body)
    	resp.Body.Close() //不要泄漏资源
    	if err != nil {
    		ch <- fmt.Sprintf("while reading %s: %v", url, err)
    		return
    	}
    	secs := time.Since(start).Seconds()
    	ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    go build fetchall.go + fetchall https://baidu.com https://google.cn

    一个Web服务器

    server1.go

    设计一个迷你回声服务器

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    )
    
    func main() {
    	http.HandleFunc("/", handler) //回声请求调用处理程序
    	log.Fatal(http.ListenAndServe("localhost:8000", nil))
    }
    
    //处理程序回显请求URL r的路径部分
    func handler(w http.ResponseWriter, r *http.Request) {
    	fmt.Fprintf(w, "URL.path = %q\n", r.URL.Path)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    cmd输入go run server1.go就会开启一个服务器
    可以cmd访问也可以直接通过浏览器访问,浏览器访问在地址栏输入localhost:8000/hello会输出URL.path = "/hello

    server2.go

    在server1的基础上新增了统计访问次数的功能

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"sync"
    )
    //同步锁
    var mu sync.Mutex
    var count int
    
    func main() {
    	http.HandleFunc("/", handler) //回声请求调用处理程序
    	http.HandleFunc("/count", counter)
    	log.Fatal(http.ListenAndServe("localhost:8000", nil))
    }
    
    //处理程序回显请求URL r的路径部分
    func handler(w http.ResponseWriter, r *http.Request) {
    	mu.Lock()
    	count++
    	mu.Unlock()
    	fmt.Fprintf(w, "URL.path = %q\n", r.URL.Path)
    }
    
    //counter显示目前为止调用的次数
    func counter(w http.ResponseWriter, r *http.Request) {
    	mu.Lock()
    	fmt.Fprintf(w, "Count %d\n", count)
    	mu.Unlock()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    其他内容

    if语句

    if err := r.ParseForm();err != nil{
    }
    //等价于 
    err := r.Parseform() 
    if err != nil{
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    但是合并的语句更短且缩小了err变量的作用域。

    Switch语句

    switch coinflip(){
    	case "heads":
    		heads++
    	case "tails":
    		tails++
    	default:
    		fmt.Println("landed on edge!")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    case语句不会像C语言那样从上到下贯穿执行(尽管有一个很少使用的fallthrough语句可以改写这个行为)

    switch语句也可以不需要操作数,它就像一个case语句列表,每条case语句都是一个布尔表达式:

    	func Signum(x int) int{
    		switch{
    			case x > 0:
    				return +1
    			default:
    				return 0
    			case x M 0:
    				return 01
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这种形式称为无标签选择,等价于switch true

    type命名类型

    type声明给已有类型命名

    type Point struct{
    	x, y int
    }
    var p Point
    
    • 1
    • 2
    • 3
    • 4

    更多

    指针
    方法和借口

    注释:不能嵌套

    使用go doc工具可以访问文档

    总结

    go给我感觉是在吸取经验的同时又舍弃了好多内容,比如–i,指针加减。
    目前来看语法看似不严谨实则要求非常统一。

  • 相关阅读:
    论文阅读笔记(二)
    C++读取系统剪贴板数据(windows)
    1300*D. Alice, Bob and Candies(模拟)
    服务器 jupyter 文件名乱码问题
    探秘Nutch:揭秘开源搜索引擎的工作原理与无限应用可能(三)
    对话框管理器第八章:对话框中的自定义导航
    STC 51单片机55——加速度计GY-29 ADXL345
    淘宝高级关键字搜索淘宝商品 API
    Biotin-LC(CAS:72040-64-3)含有的 NHS 酯起到哪些化学效应了?
    React 组件:计时器例子
  • 原文地址:https://blog.csdn.net/upset_poor/article/details/125963490