Go语言必备技能——加快你的工做效率

简介: 不管是Go语言小白,仍是有经验的开发者,均可能从中获取灵感。git

一句话技巧

把你面向对象的大脑扔到家里吧,去拥抱接口。github

学习如何使用Go的方式作事,不要把别的的编程风格强行用在Go里面。golang

多用接口总比少用好。面试

拥抱这种简洁、并行、工整的语言。编程

阅读官网golang.org上全部的文档,真是棒呆了。网络

别忘了用gofmt。数据结构

多读源代码。架构

学习工具和组件,而后创造你本身的!码代码和学代码同样对成功必不可少。运维

学而不思则罔,思而不学则殆。《论语》编程语言

引入package的多种方式

有几种很是规方式来引入包(package)。接下来我会使用fmt来做为例子:

import format "fmt" - 为fmt创造一个别名。把代码中全部使用到fmt的内容用format.代替fmt.

import . "fmt" - 容许包内的内容不加fmt前缀而被被直接引用

import _ "fmt" - 阻止编译器为引入fmt却不使用里面的内容作引起的警告,执行package中的初始化函数。提醒一句,在这种状况下fmt是不可调用的

Goimports

命令goimports能够更新您的Go导入行,添加缺乏的行,并删除未引用的引导行。

它拥有和gofmt(插入式替换)相同的能力,可是goimports额外增长了修复imports的功能。

组织

Go是一种相对来讲易学习的编程语言,但对于开发者来讲,起初接触这门语言最困难的事情就是如何组织代码。scaffolding是人们喜欢Rails的缘由之一,它能够给新晋的开发者清晰的方向,让他们明白在哪里插入代码,应该遵循怎样的编程风格。

做为扩展,Go使用go fmt这样的工具来提供开发者相同的功能。一样地,Go的编译器很是严格,它不会去编译没有使用的变量,或者没有使用的import声明。

自定义构造函数

我常常听到别人问,“我何时应该使用像NewJob这样的自定义构造函数?”,个人回答是“大多数情形下你不必这么作”。然而,当你须要在初始化的时候就设置值,且你有一些默认值的时候,这就最好使用一个构造函数。在这个例子中,构造函数就比较有意义了,所以咱们用以下的代码能够构建一个默认的logger:

package main
import (
    "log"
    "os"
)
type Job struct {
    Command string
    *log.Logger
}
func NewJob(command string) *Job {
    return &Job{command, log.New(os.Stderr, "Job: ", log.Ldate)}
}
func main() {
    NewJob("demo").Print("starting now...")
}

把代码分解到不一样的package中

以工程Gobot为例,它能够被分割为一个核心package和一些其余package。gobot的开发者们准备每一个部分放在本身的package里。通过讨论,他们选择把全部的官方库放在同一个repository下,让import路径变得干净而富有逻辑。

因此,他们不打算把路径设置为:

github.com/hybridgroup/gobot
github.com/hybridgroup/gobot-sphero
github.com/hybridgroup/gobot-...

而是设置为

github.com/hybridgroup/gobot
github.com/hybridgroup/gobot/sphero
github.com/hybridgroup/gobot/...

如今package的名字再也不是冗长的gobot-sphero,而变成了简要的sphero。

集合(Sets)

在其余的程序语言中,常常会有一种数据结构叫作sets,它容许把元素存入,可是不容许重复。Go并不直接支持这种结构,可是这个结构在Go里面的实现并不困难。

// UniqStr returns a copy if the passed slice with only unique string results.
func UniqStr(col []string) []string {
    m := map[string]struct{}{}
    for _, v := range col {
        if _, ok := m[v]; !ok {
            m[v] = struct{}{}
        }
    }
    list := make([]string, len(m))
    i := 0
    for v := range m {
        list[i] = v
        i++
    }
    return list
}

Playground连接

在这里,我会使用一些很是有意思的花招。首先,对空结构的映射:

m := map[string]struct{}{}

咱们建立了一个map,这能够确保key是独一无二的,而相关联的value实际上是咱们不关心的。
咱们固然可使用:

m := map[string]bool{}

可是,使用空结构体能够达到一样的效率,同时不会占用额外的内存。

第二个花招的意味更为深远:

if _, ok := m[v]; !ok {
  m[v] = struct{}{}
}

这里作的事情就是确认map m中的某个值是否存在,而不关心value自己。若是发现没有对应的值,就去加一个。固然,不去验证直接加好像也没有什么区别。

一旦咱们拥有了一个充满独一无二key的map之后,就能够把他们放到一个切片里,返回结果了。

这里有一段测试代码,正如你所见,这里使用了一个符合Go语言单元测试风格的表格测试:

func TestUniqStr(t *testing.T) {
    data := []struct{ in, out []string }{
        {[]string{}, []string{}},
        {[]string{"", "", ""}, []string{""}},
        {[]string{"a", "a"}, []string{"a"}},
        {[]string{"a", "b", "a"}, []string{"a", "b"}},
        {[]string{"a", "b", "a", "b"}, []string{"a", "b"}},
        {[]string{"a", "b", "b", "a", "b"}, []string{"a", "b"}},
        {[]string{"a", "a", "b", "b", "a", "b"}, []string{"a", "b"}},
        {[]string{"a", "b", "c", "a", "b", "c"}, []string{"a", "b", "c"}},
    }
    for _, exp := range data {
        res := UniqStr(exp.in)
        if !reflect.DeepEqual(res, exp.out) {
            t.Fatalf("%q didn't match %q\n", res, exp.out)
        }
    }
}

通过测试发现,并不是每次都可以成功,而是有几率的。由于map是使用hashmap实现的,使用range进行遍历的时候,其遍历顺序和字符串的内容没有必然联系,所以此test有可能失败。在进行DeapEqual比对的时候,可能会爆出相似于["b" "c" "a"] didn't match ["a" "b" "c"]的错误。固然,在Playground中,每次执行的上下文环境如出一辙,所以这里的test是总能经过的。

依赖包管理

很遗憾,Go语言官方并不提供依赖包管理系统。这极可能是由于go语言植根于C语言的文化,所以它没有办法引入特定版本的包。

这会带来一些严重的问题:

1.当多个开发者共同维护一个项目时,不一样开发者的依赖版本可能不一样。
2.依赖也会有他们自身的依赖,因此很难确保全部的依赖都使用同一个版本。
3.你的多个项目基于了同一个依赖的不一样版本。

对于最后一种情形,能够经过搭建一个_持续集成环境(Continuousintegration)来解决,可是前二者就相对困难。

※部分文章来源于网络,若有侵权请联系删除;更多文章和资料|点击后方文字直达 ↓↓↓
100GPython自学资料包
阿里云K8s实战手册
[阿里云CDN排坑指南] CDN
ECS运维指南
DevOps实践手册
Hadoop大数据实战手册
Knative云原生应用开发指南
OSS 运维实战手册
云原生架构白皮书
Zabbix企业级分布式监控系统源码文档
10G大厂面试题戳领
相关文章
相关标签/搜索