意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

我什么时候应该使用像NewJob这样的自定义构造函数?

来源:恒创科技 编辑:恒创科技编辑部
2024-01-31 22:12:59

今天小编给大家分享一下Go语言加快工作效率的使用技巧有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

引入package的多种方式

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

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


我什么时候应该使用像NewJob这样的自定义构造函数?

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

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

Goimports

命令goimports可以更新您的Go导入行,添加缺少的行,并删除未引用的引导行。

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

组织

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

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

自定义构造函数

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

packagemain
import(
"log"
"os"
)
typeJobstruct{
Commandstring
*log.Logger
}
funcNewJob(commandstring)*Job{
return&Job{command,log.New(os.Stderr,"Job:",log.Ldate)}
}
funcmain(){
NewJob("demo").Print("startingnow...")
}

把代码分解到不同的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里面的实现并不困难。

//UniqStrreturnsacopyifthepassedslicewithonlyuniquestringresults.
funcUniqStr(col[]string)[]string{
m:=map[string]struct{}{}
for_,v:=rangecol{
if_,ok:=m[v];!ok{
m[v]=struct{}{}
}
}
list:=make([]string,len(m))
i:=0
forv:=rangem{
list[i]=v
i++
}
returnlist
}

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语言单元测试风格的表格测试:

funcTestUniqStr(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:=rangedata{
res:=UniqStr(exp.in)
if!reflect.DeepEqual(res,exp.out){
t.Fatalf("%qdidn'tmatch%q\n",res,exp.out)
}
}
}

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

依赖包管理

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

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

当多个开发者共同维护一个项目时,不同开发者的依赖版本可能不同。

2.依赖也会有他们自身的依赖,所以很难确保所有的依赖都使用同一个版本。 3.你的多个项目基于了同一个依赖的不同版本。

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

以上就是“Go语言加快工作效率的使用技巧有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注恒创行业资讯频道。

上一篇: 弹性web托管指的是什么 下一篇: 手机怎么远程登录云服务器?