Go语⾔学习三实例详解
本⽂最初发表在我的个⼈博客,欢迎查看原⽂:
介绍了Go代码的组织结构及⼀些基本概念,下⾯将以github/favorstack作为基路径,在⼯作空间中创建⼀个⽬录来保存源代码,介绍⼀下基本的语法。
⼀第⼀个程序
Hello world程序
1). 创建基路径:
$ mkdir -p $GOPATH/src/github/favorstack
或者:
$ mkdir -p ~/go/src/github/favorstack
2). 新建⼀个⼯程⽬录go-example:
该⽬录可以作为git仓库的根⽬录:
$ cd$GOPATH/src/github/favorstack &&mkdir go-example
3). 在上述⽬录下创建hello⽬录:
$ cd go-example &&mkdir hello
4). 在hello⽬录下新建⼀个⽂件:
$ cd hello &&
然后输⼊以下代码:
package main
import"fmt"
func main(){
fmt.Println("Hello World!")
}
5). 保存退出。
6). 编译执⾏
在第⼀篇⽂章中我们已经使⽤过go build命令了,这次我们直接安装到$GOPATH⽬录的bin下:
执⾏go install命令编译并安装:
$ go install
没有任何信息输出则表⽰编译没问题。
直接执⾏~/go/bin下的命令,需要将该⽬录添加到$PATH环境变量中,如果你还没有加上,现在是个好机会,可以参考。
没问题的话,我们可以看到可执⾏程序已经编译好并安装在~/go/bin⽬录下了,直接执⾏hello命令即可(Windows下是):
$ hello
Hello World!
上⾯省略了包路径,只能在当前⽬录下执⾏。如果加上包路径,则可以在任意位置执⾏:
$ go install github/favorstack/go-example/hello
在不指定包路径时,go install会从当前⽬录查源代码,⽽指定包路径后,会从$GOPATH指定的位置查github/favorstack/go-example/hello包的源代码,所以在指定了包路径后,⽆需在当前⽬录下执⾏安装命令。
另外,源代码⽂件未改变(MD5值未改变)的情况下,多次执⾏go isntall所编译安装的可执⾏程序并不会发⽣改变,实际上,go甚⾄并未进⾏新的编译⽽是直接复制的第⼀次编译后的结果,你可以对⽬标⽂件执⾏MD5值校验多次编译的结果来验证这⼀点。
代码解释
<源⽂件后缀必须以.go结尾:
例如
<代码的第⼀⾏有效(⾮注释)代码总是以包的声明开始:
例如package main
3.包的声明语法:
package 包名
包名即为在其他模块导⼊时使⽤的名称,同⼀个包下的所有源⽂件必须使⽤相同的包名。包名应该尽量简短,简洁,好记,按照约定,所有包名使⽤⼩写字母,且使⽤单个单词表⽰,不需要使⽤下划线或⼤⼩写混合的⽅式。
在Go语⾔中,有⽤的⽂档注释通常⽐超长名称更有价值
4.导⼊包语法:
import "包导⼊路径"
多个导⼊包需要放到括号中:
import (
"包路径1"
"包路径2"
...
)
5.重命名导⼊:
如果导⼊的包具有相同的包名时,需要重命名其中⼀个包名:
import (
"path1/package"
mypackage "path2/package"go语言安装教程
)
其中,左侧为新的包名mypackage,右侧为原始包名"path2/package"
命令 go doc [command]可以查询指定包的⽤法, 例如go doc net/http
6.Go语句的结尾
Go语句⽆需以分号;结尾,但是如果多条语句放在⼀⾏,则需要⽤分号隔开,我们并不推荐这种多条语句放在⼀⾏的⽤法。
⼆第⼀个库
字符串反转⼯具
接下来是⼀个字符串反转的⼩⼯具⽰例。
1). ⾸先创建包路径:
$ mkdir$GOPATH/src/github/favorstack/go-example/stringutil
2). 接下来在上⾯的⽬录下创建⽂件:
$ cd stringutil &&
3). 输⼊以下内容:
// stringutil包包含字符串处理相关的函数
package stringutil
// Reverse函数返回其参数字符串从左到右的反转形式
func Reverse(s string)string{
r :=[]rune(s)
length :=len(r)
for i, j :=0, length -1; i < length/2; i, j = i +1, j -1{
r[i], r[j]= r[j], r[i]
}
return string(r)
}
4). 然后⽤go build编译⼀下:
$ go build github/favorstack/go-example/stringutil
或者如果你当前已经在stringutil⽬录下了的话,直接执⾏go build即可:
# if currently in github/favorstack/go-example/stringutil
$ go build
需要注意的是,本次编译并不会像⼀样产⽣编译后的⽂件,实际上,它已经把编译好的包放到了本地缓存中。
5). 接下来修改我们的程序使⽤刚才编写的Reverse函数:
package main
import(
"fmt"
// 导⼊字符串⼯具包
"github/favorstack/go-example/stringutil"
)
func main(){
fmt.Println("Hello World!")
s :="悠云⽩雁过南楼"
fmt.Println(s)
// 使⽤反转函数
fmt.Println(stringutil.Reverse(s))
}
6). 然后保存安装:
$ go install github/favorstack/go-example/hello
7). 运⾏:
$ hello
Hello World!
悠云⽩雁过南楼
楼南过雁⽩云悠
现在,⼯作空间的⽬录结构应该是这样:
~/go/ # GOPATH
bin/
hello # 可执⾏⽂件
src/
github/favorstack/go-example/
hello/
< # 可执⾏⽂件源⽂件
stringutil/
< # ⼯具包源⽂件
代码解释
1.包名需要与导⼊路径的最后⼀个元素保持⼀致;
虽然语法上源⽂件的包名可以和导⼊路径的最后⼀个元素不⼀样,但是按照Go的约定,我们⼀般习惯将包名与导⼊路径的最后⼀个元素保持⼀致
例如,⽰例中的导⼊路径github/favorstack/go-example/stringutil(在中),包名对应的为stringutil(在中);
另外,可执⾏⽂件的包总是声明为package main,Go会查main包下的main()函数作为程序⼊⼝。
假如我们将放到github/favorstack/go-example/util下,但是声明依然是package stringutil,那么,相应的导⼊路径会变
为github/favorstack/go-example/util,但是如果你试图使⽤util来调⽤其中的函数:util.Reverse(...),则会报错:
$ go build
# github/favorstack/go-example/hello
./:5:2: imported and not used: "github/favorstack/go-example/util" as stringutil
./:12:14: undefined: util
上述错误包含两点:
1) imported and not used: "github/favorstack/go-example/util" as stringutil
提⽰stringutil包导⼊后未曾使⽤(实际⽤的是util)。在Go中,不允许导⼊的包不使⽤,即不允许多余的包导⼊,这样会造成资源浪费,所以Go直接从语⾔层⾯上就禁⽌了这种做法。当然,这⼀点还有另⼀种折中的办法来导⼊不使⽤的包,参见下⾯的空⽩标识符;
2)undefined: util
提⽰未定义的包util(实际定义的是stringutil)。
因为包的名字实际上还是叫stringutil,因此,依然需要使⽤stringutil.Reverse(...)。所以为了不必要的
⿇烦和误解,请⼀定要将包名与导⼊路径的最后⼀个元素保持⼀致
2.变量的声明
在中,有如下两⾏代码:
r :=[]rune(s)
length :=len(r)
符号:=在Go中称作简化变量声明运算符。这个运算符⽤于声明⼀个变量,同时给这个变量赋予初始值。编译器使⽤函数返回值的类型来确定每个变量的类型。简化变量声明运算符只是⼀种简化记法,让代码可读性更⾼。
另外,Go还有⼀种声明变量的⽅式:
var 变量名变量类型
例如:
// 声明⼀个类型为string的变量s
var s string
使⽤关键字var声明的变量和简化变量声明运算符:=声明的变量没有任何区别。⼀般情况下,要声明初始值为零值的变量,应该使⽤var关键字声明变量;如果提供确切的⾮零初始化变量或者使⽤函数返回值创建变量,应该使⽤简化变量声明运算符。
3.注释
与⼤多数语⾔⼀样,在Go中,以//开头的⾏表⽰注释
三测试
第⼀个测试代码
Go⾃⾝带有⼀个由go test和testing包组成的轻量级测试框架。
⾸先在$GOPATH/src/github/favorstack/go-example/stringutil⽬录下创建⼀个测试⽂件,内容如下:
package stringutil
import"testing"
func TestReverse(t *testing.T){
cases :=[]struct{
in, want string
}{
{"Hello, world!","!dlrow ,olleH"},
{"悠云⽩雁过南楼","楼南过雁⽩云悠"},
{"",""},
}
for_, c :=range cases {
got :=Reverse(c.in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
}
}
}
保存退出,然后在当前⽬录运⾏测试:
$ go test
PASS
ok github/favorstack/go-example/stringutil 0.007s
或者在任意位置运⾏测试:
$ go test github/favorstack/go-example/stringutil
ok github/favorstack/go-example/stringutil 0.007s
代码解释
1.Go测试⽂件格式
Go测试⽂件必须以_结尾,测试函数必须以Test开头,形如TestXxx格式,Xxx必须以⼤写字母开头,且函数参数签名必须是func (t *testing.T)形式。测试框架会执⾏每⼀个这样的函数,如果某个这样的函数调⽤了像t.Error 或 t.Fail这样的失败函数,则该测试没有通过。
2.struct关键字
Go使⽤struct关键字声明⾃定义结构类型。
现在只需要知道,这段代码声明了⼀个元素为⾃定义结构类型的切⽚(cases变量),该⾃定义结构类型有两个字符串类型的字段(或者叫属性)in,want,并且该切⽚默认初始化了3个元素。切⽚也是⼀种数据结构,有点像动态的数组。切⽚是可以进⾏迭代的。
cases :=[]struct{
in, want string
}{
{"Hello, world!","!dlrow ,olleH"},
{"悠云⽩雁过南楼","楼南过雁⽩云悠"},
{"",""},
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论