Go语言培训

本课程培训目标

通过本课程能编写Go的Web小程序,让大家对Go有点小兴趣

哪些公司、平台在使用Go语言

B站、七牛云、K8s

Go语言优势

占用内存小,并发编程上手简单
适合容器化部署
适合C语言程序员上手

Go语言劣势

第三方类库没有java丰富

Go语言特征

1.自动立即回收
2.更丰富的内置类型
3.函数多返回值
4.错误处理
5.匿名函数和闭包
6.类型和接口
7.并发编程
8.反射
9.语言交互性

Go没有的语言特征

没有继承,不面向对象

Go语言基础语法

  1. 关键字import、if else、for(没有while)、switch、指针
  2. 特性:
  3. 高级特性: 协程、管道Channel

Hello world

1.安装Go,下载地址

##查看go版本
go version

2.安装IDE。可以使用VSCode(前端经验入门), Idea的GoLand(java经验入门)
3.创建文件夹go-playground,使用Idea打开这个文件夹
4.在根目录下,创建main.go

package main
import "fmt"

func hello() {
  return "Hello, world"
}

func main() {
    fmt.Println("hello world!")
}
  1. 使用go官方的包(package)依赖管理工具go mod,go mod等同于maven、npm、cocoapads等。包依赖管理这个我们下节课在仔细讲。
    在根目录(go-playground)执行: go mod init github.com/wongben/go-playground
    执行后在根目录生成文件go.mod。内容如下:
module github.com/wongben/go-playground
go 1.12

6.在命令行里执行

go build //生成go-playground.exe文件
go run main.go //编译和执行main.go

7.编写测试案例

package main

import "testing"

func TestHello(t *testing.T) {
    got := Hello()
    want := "Hello, world"

    if got != want {
        t.Errorf("got '%q' want '%q'", got, want)
    }
}

编写测试和函数很类似,其中有一些规则:

  • 程序需要在一个名为 xxx_test.go 的文件中编写
  • 测试函数的命名必须以单词 Test 开始
  • 测试函数只接受一个参数 t *testing.T
    现在这些信息让我们明白: 类型为 *testing.T 的变量 t 是你在测试框架中的 hook(钩子),所以当你想让测试失败时可以执行 t.Fail() 之类的操作。

接下来我们把测试类重构一下

package hello

import "testing"

func TestHello(t *testing.T) {
    assertCorrectMessage := func(t *testing.T, got, want string) {
        t.Helper()
        if got != want {
            t.Errorf("got '%q' want '%q'", got, want)
        }
    }

    t.Run("saying hello to people", func(t *testing.T) {
        got := Hello("ben", "en")
        want := "hello, ben"
        assertCorrectMessage(t, got, want)
    })

    t.Run("中文测试", func(t *testing.T) {
        got := Hello("ben","cn")
        want := "你好, ben"
        assertCorrectMessage(t, got, want)
    })

}

这里我们将使用测试库中的另一个工具 -- 子测试。有时,对一个「事情」进行分组测试,然后再对不同场景进行子测试非常有效。
这种方法的好处是,你可以建立在其他测试中也能够使用的共享代码。
当我们检查信息是否符合预期时,会有重复的代码。重构不仅仅是针对程序的代码

int整型

首先,先写测试
这里,我们可以通过编写 示例 更深入地了解测试,标准库的文档中能够找到许多这样的例子。与典型的测试一样,示例是存在于一个包的 _test.go 文件中的函数。向 adder_test.go 文件添加以下 ExampleAdd 函数。

package integers

import (
    "fmt"
    "testing"
)


func ExampleAdd() {
    sum := Add(1, 5)
    fmt.Println(sum)
    // Output: 6
}

func TestAdd(t *testing.T) {
    sum := Add(2, 2)
    expected := 4

    if sum != expected {
        t.Errorf("expected '%d', but got '%d'", expected, sum)
    }
}
package integers

func Add(x, y int) int{
    return x + y
}

迭代与基准测试

在 Go 中 for 用来循环和迭代,Go 语言没有 while,do,until 这几个关键字,你只能使用 for。

func main() {
    sum := 1
    //初始化语句和后置语句是可选的,等效于for ; sum < 1000; {
        for  sum < 1000  {
        sum += sum
    }
    fmt.Println(sum)
}

迭代

const repeatCount = 5

func Repeat(character string) string {
    var repeated string
    for i := 0; i < repeatCount; i++ {
        repeated += character
    }
    return repeated
}

基准测试

在 Go 中编写基准测试(benchmarks)是该语言的另一个一级特性,它与编写测试非常相似。

func BenchmarkRepeat(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Repeat("a")
    }
}

你会看到上面的代码和写测试差不多。
testing.B 可使你访问隐性命名(cryptically named)b.N。基准测试运行时,代码会运行 b.N 次,并测量需要多长时间。代码运行的次数不会对你产生影响,测试框架会选择一个它所认为的最佳值,以便让你获得更合理的结果。
用 go test -bench=. 来运行基准测试。

数组与分片

  • 先写测试函数
package arrays

import "testing"

func TestSum(t *testing.T) {
    //var n [5]int
    //numbers := [5]int{}
    //numbers := [5]int{1,2,3,4,5}
    //numbers := []int{1,2,3,4,5}
    numbers := [...]int{1,2,3,4,5}
    got := sum(numbers)

    want := 15
    if want != got {
        t.Errorf("got %d want %d given, %v", got, want, numbers)
    }
}

数组的容量是我们在声明它时指定的固定值。我们可以通过两种方式初始化数组:
[N]type{value1, value2, ..., valueN} e.g. numbers := [5]int{1, 2, 3, 4, 5}
[...]type{value1, value2, ..., valueN} e.g. numbers := [...]int{1, 2, 3, 4, 5}

在错误信息中打印函数的输入有时很有用。我们使用 %v(默认输出格式)占位符来打印输入,它非常适用于展示数组。

  • 先使用最少的代码来让失败的测试先跑起来
package arrays

func Sum(numbers [5]int) (sum int) {
    return 0
}

//func Sum(numbers [5]int) (sum int) {
//  for i := 0; i < 5; i++ {
//      sum += numbers[i]
//  }
//  return sum
//}

//func Sum(numbers [5]int) (sum int) {
//  for _, number := range numbers {
//      sum += number
//  }
//  return sum
//}
  • 数组和它的类型

数组有一个有趣的属性,它的大小也属于类型的一部分,如果你尝试将 [4]int 作为 [5]int 类型的参数传入函数,是不能通过编译的。它们是不同的类型,就像尝试将 string 当做 int 类型的参数传入函数一样。

因为这个原因,所以数组比较笨重,大多数情况下我们都不会使用它。

Go 的切片(slice)类型不会将集合的长度保存在类型中,因此它的尺寸可以是不固定的。
下面我们会完成一个动态长度的 Sum 函数。

func Sum(numbers []int) (sum int) {
    for _, number := range numbers {
        sum += number
    }
    return sum
}

我们可以使用 range语法来让函数变得更加整洁。range 会迭代数组,每次迭代都会返回数组元素的索引和值。我们选择使用 _ 空白标志符 来忽略索引。

  • 重构
    我们已经重构了 Sum 函数把参数从数组改为切片。注意不要在重构以后忘记维护你的测试代码。
func TestSum(t *testing.T) {

    t.Run("collection of 5 numbers", func(t *testing.T) {
        numbers := []int{1, 2, 3, 4, 5}

        got := Sum(numbers)
        want := 15

        if got != want {
            t.Errorf("got %d want %d given, %v", got, want, numbers)
        }
    })

    t.Run("collection of any size", func(t *testing.T) {
        numbers := []int{1, 2, 3}

        got := Sum(numbers)
        want := 6

        if got != want {
            t.Errorf("got %d want %d given, %v", got, want, numbers)
        }
    })

}

Go 有内置的计算测试 覆盖率的工具,它能帮助你发现没有被测试过的区域。我们不需要追求 100% 的测试覆盖率,它只是一个供你获取测试覆盖率的方式。只要你严格遵循 TDD 规范,那你的测试覆盖率就会很接近 100%。

运行:
go test -cover

  • 另一个例子
    这回我们需要一个 SumAll 函数,它接受多个切片,并返回由每个切片元素的总和组成的新切片。
    例如:SumAll([]int{1,2}, []int{0,9}) 返回 []int{3, 9}
    或者: SumAll([]int{1,1,1}) 返回 []int{3}

先编写测试


func TestSumAll(t *testing.T) {

    got := SumAll([]int{1,2}, []int{0,9})
    want := []int{3, 9}

    if got != want {
        t.Errorf("got %v want %v", got, want)
    }

https://www.jianshu.com/p/0cbc97bd33fb

你可能感兴趣的:(Go语言培训)