go笔记

学习网站:https://studygolang.gitbook.io/learn-go-with-tests/go-ji-chu/hello-world#bian-xie-ce-shi

编写测试

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

 

  • 程序需要在一个名为 xxx_test.go 的文件中编写

  • 测试函数的命名必须以单词 Test 开始

  • 测试函数只接受一个参数 t *testing.T

现在这些信息足以让我们明白,类型为 *testing.T 的变量 t 是你在测试框架中的 hook(钩子),所以当你想让测试失败时可以执行 t.Fail() 之类的操作。

 

t.Errorf

我们调用 tErrorf 方法打印一条消息并使测试失败。error后面的f 表示格式化,它允许我们构建一个字符串,并将值插入占位符值 %q 中。当你的测试失败时,它能够让你清楚是什么错误导致的。

 

 

介绍了一种叫做TDD的程序设计方法论,即测试驱动开发(Test-Driven development)

去查了一下这个东西:https://juejin.cn/post/6844903925842198536

TDD三原则

  1. 除非为了通过一个单元测试,否则不允许编写任何产品代码。
  2. 在一个单元测试中只允许编写刚好能够导致失败的内容。
  3. 一次只能写通过一项单元测试的产品代码,不能多写。
  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
太难用了

 

 

 

3.6

for循环

go里面没有whiledountil 这几个关键字,

for循环的变体

package main

import "fmt"

func main() {

	i := 1
	for i <= 3 {
		fmt.Println(i)
		i = i + 1
	}
	fmt.Println("")

	for j := 7; j <= 9; j++ {
		fmt.Println(j)
	}
	fmt.Println("")

	for {
		fmt.Println("loop")
		break
	}
	fmt.Println("")

	for n := 0; n <= 5; n++ {
		if n%2 == 0 {
			continue
		}
		fmt.Println(n)
	}
	fmt.Println("")
}
// 1
// 2
// 3

// 7
// 8
// 9

// loop

// 1
// 3
// 5
数组

 

数组的容量是我们在声明它时指定的固定值。我们可以通过两种方式初始化数组:
[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}
举个栗子:
number := [5]int{1, 2, 3, 4, 5}

 
空白标志符
看两个代码
array := [5]int{1, 2, 3, 4, 5}
s := 0
for i, arr := range array {
	s += arr
	fmt.Println("i=", i, "  s=", s, "  arr=", arr)
}
// i= 0   arr 1   s=%d 1
// i= 1   arr 2   s=%d 3
// i= 2   arr 3   s=%d 6
// i= 3   arr 4   s=%d 10
// i= 4   arr 5   s=%d 15
array := [5]int{1, 2, 3, 4, 5}
s := 0
for _, arr := range array {
	s += arr
	fmt.Println("  s=", s, "  arr=", arr)
}
// s= 1   arr= 1
// s= 3   arr= 2
// s= 6   arr= 3
// s= 10   arr= 4
// s= 15   arr= 5

 空白标识符可以接收一个不需要用的参数,最常用的地方就是在 使用range 迭代数组时,每次迭代都会返回数组元素的索引和值。我们选择使用 _ 空白标志符 来忽略索引。

 

 

 

3.7

函数

函数可变参数

func SumAll(numberToSum ...[]int) (sums []int) {
	return
}

 

 

 方法 reflect.DeepEqual

这个方法在比较两个数组元素是否完全相同时很好用

func TestSumAll(t *testing.T) {
	got := SumAll([]int{1, 2}, []int{0, 9})
	want := []int{3, 9}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("got %v want %v", got, want)
	}
}

 两个数组完全相同返回true,否则返回false

 

 

方法make

一种创建切片的新方式。make 可以在创建切片的时候指定我们需要的长度和容量。
我们可以使用切片的索引访问切片内的元素,使用 = 对切片元素进行赋值。

sums = make([]int, lengthOfNumbers)

 

切片处理

使用语法 slice[low:high] 获取部分切片,比如

numbers[1:4]

 就可以获取到从第二个到第五个元素,如果在冒号的一侧没有数字就会一直取到最边缘的元素,比如

numbers[1:]

 就可以获取到从第二个开始到最后的元素

 

结构体

go定义结构体和c语言一样,在定义方法时有所区别,不过在调用的时候是一样的

type Rectangle struct {
	//矩阵
	Width  float64
	Height float64
}

func (r Rectangle) Area() float64 {
	return (r.Height * r.Width)
}

type Circle struct {
	//圆
	Radius float64
}

func (r Circle) Area() float64 {
	return (math.Pi * r.Radius * r.Radius)
}

rectangle := Rectangle{12.0, 6.0}
got := rectangle.Area()    
circle := Circle{10.0}
got := circle.Area()

 

 接口

 https://www.zhihu.com/question/318138275

稍微学习了一下接口的意思,但还是比较模糊。知乎里说到的鸭子模型,只要它能达到我所设置的成为鸭子的条件,那它就是鸭子。

package main

import (
	"fmt"
)

//手机接口
type Phone interface {
	call()
}

type NokiaPhone struct {
}

func (nokiaPhone NokiaPhone) call() {
	fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {
}

func (iPhone IPhone) call() {
	fmt.Println("I am iPhone, I can call you!")
}

//电脑接口
type Computer interface {
	play()
}

type PersonalComputer struct {
}

func (personalcomputer PersonalComputer) play() {
	fmt.Println("I am personalcomputer")
}

type LapTop struct {
}

func (laptop LapTop) play() {
	fmt.Println("I am laptop")
}

//乱入了一台假装自己是手机的笔记本
func (laptop LapTop) call() {
	fmt.Println("I can be a phone ")
}

func main() {
	var phone Phone

	phone = new(NokiaPhone)
	phone.call()

	phone = new(IPhone)
	phone.call()

	phone = new(LapTop)
	phone.call()

	var computer Computer
	computer = new(PersonalComputer)
	computer.play()
	computer = new(LapTop)
	computer.play()
	// computer.call()

	
	
	
	
}

 可以看到在两种手机,两种电脑中,乱入了一台假装自己是手机的电脑,当LapTop定义了这样两个方法后,它即实现了手机这个接口,又实现了电脑这个接口。于是出现了下面的情况

phone = new(LapTop)
phone.call()
computer = new(LapTop)
computer.play()

 但是只得注意的是,computer.call()并不能执行,虽然这里的computer本质是LapTop,而LapTop有call()这个方法,但是因为接口的关系,它在这里只能成为computer(好像有点绕)

用蓝皮书上说的,接口就是一种约定

 

posted @ 2021-03-06 22:58  This_is_Y  阅读(114)  评论(0编辑  收藏  举报