Go笔记_1
方法
- Go语言中只有不同的
package
中可以有相同函数名的函数,尽管参数不同,但是如果函数名相同就不能出现在相同的包中(函数重载Go语言没有) - 方法需要通过一个特定的实例调用,比如
t.Errorf()
,这里的Errorf
就是一个方法,通过实例t
调用 - 函数可以随便调用,没有限制
接口
- 接口让函数接受不同类型的参数并创造类型安全并且高解耦的代码
- Go语言中 interface resolution 是隐式的。如果传入的类型匹配接口需要的,则编译正确。
- 函数实现因此不需要关心参数是什么类型的,只需要声明一个接口,辅助函数就可以从具体类型解耦而只关心本身需要做的工作
表格驱动测试
- 如果需要测试一个接口的不同实现,或者传入的数据有很多不同的测试需求,则可以使用表格驱动测试
1 | func TestArea(t *testing.T){ |
- 创建了一个匿名结构体,里面有shape和want,放在一个[]struct切片中
- 然后使用两个测试用例填充这个切片
- Go中调用一个函数或者方法的时候,参数会被复制
- 使用指针解决这个问题,指向某个值,然后修改
map
- Map是引用类型的,拥有对底层数据结构的引用
- 因此,Map可以是nil指,如果使用一个nil的map,那么会得到一个nil指针异常,导致程序终止
- 永远不要初始化一个空的map变量,比如:
var m map[string]string
- 可以用如下两种方式初始化空的map:
1 | dict = map[string]string{} |
- 上述两种方法绝对不会出现nil指针异常
依赖注入
fmt.Fprintf
接受一个Writer
参数,将字符串传递过去。fmt.Printf
是标准的默认输出
1 | // di.go |
1 | // di_test.go |
- Go中可以使用反引号创建字符串,允许将字符串中的东西放在新的一行,比如
`
3
1
2
`
-
Go中不会阻塞的操作在成为goroutine的单独进程中运行。使用go关键字声明
-
go test -race
可以发现goroutine
中的竞争条件,比如可能多个进程同时写一个map
,但是一次执行并不会触发这种现象。 -
可以通过
channels
协调goroutine
解决数据竞争问题。 -
比如原本需要将多个进程的数据写入
map
中,现在可以使用channel <- data
,将数据发送到channel
中,然后再使用for
循环,将数据保存保存在新的map中,这样不会产生数据竞争的问题。result := <- channel
-
在函数调用之前加上
defer
前缀会在包含他的函数结束时调用它。- 有时候需要清理资源,比如在函数结束时关闭一个文件,或者关闭一个服务器,但是要把它放在创建服务器语句附近,以便函数内后面的代码仍然可以使用这个服务器,就可以使用
defer
,等到函数执行完再调用
- 有时候需要清理资源,比如在函数结束时关闭一个文件,或者关闭一个服务器,但是要把它放在创建服务器语句附近,以便函数内后面的代码仍然可以使用这个服务器,就可以使用
进程同步
select
可以轻易实现进程同步
1 | func Racer (a, b string) (winner string, err error){ |
- 如果是
v := <- ch
等待值发送给channel
,则这是一个阻塞调用,因为需要等待值返回 select
允许多个channel
等待,第一个发送值的channel
胜出。- 使用
select
时,time.After
是一个很好用的函数,因为channel
可能永远不会返回一个值,那就有可能不会返回,因此使用time.After
设置超时时间
1 | t.Run("returns an error if a server doesn't respond within 10s", func(t *testing.T) { |
反射
编写函数
walk(x interface{}, fn func(string))
,参数为结构体x,并对 x 中的所有字符串字段调用 fn 函数
- 反射提供了程序检查自身结构体的能力。
- 允许使用类型
interface{}
,代表任意类型。但是这样市区了对类型安全的检查,编译器不会再检查类型 - 除非真的需要,否则不要使用反射
- 如果想要实现多态,可以考虑围绕接口实现。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Sangs Blog!