go——工程结构
Go是一门推崇软件工程理念的编程语言,它为开发周期的每个环节都提供了完备的工具和支持。
Go语言高度强调代码和项目的规范和统一,这几种体现在工程结构或者说代码体制的细节之处。
1.工作区
一般情况下,Go源码文件必须放在工作区中。但是对于命令源码文件来说,这不是必须的。
工作区其实就是一个对应于特定工程的目录,它应该包含3个子目录:src目录、pkg目录和bin目录。
(1)src目录
用于以代码包的形式组织并保存Go源码文件,这里的代码包与src下的子目录一一对应。
例如,若一个源码文件被声明属于代码包log,那么它就应该保存在src/log目录下。
当然,你也可以直接把Go源码文件直接放在src目录下,但这样的Go源码文件就只能被声明属于main代码包。
除非用于临时测试或演示,一般还是建议把Go源码文件放入特定的代码包中。
(2)pkg目录
用于存放通过go install命令安装后的代码包的归档文件。
前提是代码包中必须包含Go库源码文件。归档文件是指那些名称以“.a”结尾的文件。
该目录与GOROOT目录下的pkg目录功能类似。
区别在于,工作区中的pkg目录专门用来存放用户代码的归档文件。
编译和安装用户代码的过程一般会以代码包为单位进行。
比如log包被编译安装后,将生成一个名为log.a的归档文件,并存放在当前工作区的pkg目录下的平台相关目录中。
(3)bin目录
与pkg目录类似,在通过go install命令完成安装后,保存由Go命令源码文件生成的可执行文件。
(其实上面文字的意思就是什么类型的文件放在什么目录下面,尽量规划好工作区)
命令源码文件:就是声明属于main代码包并包含无参声明和结果声明的main函数的源码文件。
	这类源码文件就是程序的入口,它们可以独立运行(使用go run命令),
	也可以通过go build或go install命令得到相应的可执行文件。
库源码文件:是指存在于某个代码包中普通源码文件。
2.源码文件
(1)命令源码文件
如果一个源码文件被声明属于main代码包,且该文件代码中包含无参数声明和结果声明的main函数,则它就是命令源码文件。
命令源码文件可以直接通过go run命令直接启动运行。
同一个代码中的所有的源码文件,其所属代码包的名称必须一致。
如果命令源码文件和库源码文件处于同一个代码包中,那么在该包中就无法正确执行go build和go install命令。
换句话说,这些源码文件将无法通过常规方法编译和安装。
因此,命令源码文件通常会单独放在一个代码包中,因为通常一个程序模块或软件的启动入口只有一个。
同一个代码包中可以有多个命令源码文件,可通过go run命令分别运行,但这会使go build和go install命令无法编译和安装该代码包。
当代码包中有且只有一个命令源码文件时,在文件所在目录中执行go build命令,
则可在该目录下生成一个与目录同名的可执行文件;

若使用go install命令,则可在当前工作区的bin目录下生成相应的可执行文件。


需要注意的是,只有当前环境变量GOPATH中只包含一个工作区的目录路径时,
go install命令才会把命令源码文件安装到当前工作区的bin目录下;
(2)库源码文件
通常,库源码文件声明的包名会与它直接所属的代码包一致,且库源码文件中不包含无参数声明和无结果声明的main函数。

通过执行go install命令,成功安装了该包并生成了若干归档文件。
由于我们指定了工作区GOPATH的路径是/root/example.v2,则会在这个目录下生成bin和pkg文件。
run install之前:

run install之后:

(3)测试源码文件
测试源码文件是一种特殊的库文件,可以通过执行go test命令运行当前代码包下的所有测试源码文件。
成为测试源码文件的充分条件有两个:
	  A.文件名需要以"_test.go"结尾
	  B.文件中需要至少包含一个名称以Test开头或Benchmark开头,且拥有一个类型为*testing.T或*testing.B的参数的函数。
		  *testing.T或*testing.B是两个结构体类型。而*testing.T或*testing.B则分别为前两者的指针类型。它们分别是功能测试和基准测试所需。

当在一个代码包中之心go test命令时,该代码包中的所有测试源码文件会被找到并运行。
3.代码包
在Go中,代码包是代码编译和安装的基本单元,也是非常直观的代码组织形式。
(1)包声明
在Go语言中,代码包中的源码文件可以任意命令。
但是,这些任意名称的源码文件都必须以包声明语句作为文件代码中的第一行。
例如,example.v2/src/gopcp.v2/helper/log/base包中的所有源码文件都先声明自己属于某一个代码包:

分别打印第一行:

其中,package是Go中用于包声明语句的关键字。
Go规定包声明中的包名是代码路径的最后一个元素。

所以包名是base。
但是,不论命令源文件存放在哪个代码包中,它都必须声明属于main包。
(2)包导入
代码包gopcp.v2/helper/log中的logger.go需要依赖base子包和logrus子包,
因此需要在源码文件中使用代码包导入语句,如:
import "gopcp.v2/helper/log/base"
import "gopcp.v2/helper/log/logrus"
全路径是:/root/example.v2/src/gopcp.v2/helper/log,但是所有的源代码都在src下面,所以这里使用相对路径。
当导入多个代码包时,你需要用圆括号,每个代码包名占一行。
import (
"gopcp.v2/helper/log/base"
"gopcp.v2/helper/log/logrus"
)
同一个源码文件中导入多个代码包的最后一个元素不能重复,否则一旦使用其中的程序实体,就会引起编译错误。
但是,如果你只导入不适用,同样会引起编译错误,一个解决办法就是为其中一个起别名。
import (
"gopcp.v2/helper/log/logrus"
mylogrus "gopcp.v2/helper/log/logrus"
)
如果我们想不加前缀而直接使用某个依赖包中的程序实体,就可以用"."来代替别名。
import (
. "gopcp.v2/helper/log/logrus"
)
所以我们就可以这样引用:
var logger = NewLogger("gopcp") //NewLogger是logrus中的一个函数。
我们可以看到,因为"."的缘故,可以直接引用包中的函数,而不需要指定路径。
在Go中,变量、常量、函数和类型声明可统称为程序实体,而它们的名称统称为标识符。
标识符可以是Unicode字符集中任意能表示自然语言文字的字符、数字以及下划线(_)。标识符不能以数字或下划线开头。
实际上,标识符的首字符的大小写控制着对应程序实体的访问权限。
如果标识符的首字符是大写形式,那么它所对应的程序实体就可以被本代码之外的代码访问到,也称之为可导出或公开的;
否则,对应的程序实体就只能被本包内的代码访问,也成为不可导出的或包私有的。
要想成为可导出的程序实体,还需要额外满足以下两个条件。
	程序实体必须是非局部的。局部的程序实体是指:它被定义在了函数或结构体的内部。
	代码包所属目录必须包含在GOPATH中定义的工作区目录中。
代码包导入还有另一种情况:如果只想初始化某个代码包,
而不需要在当前源码文件中使用那个代码包中的任何程序实体,就可以用“_”来代替别名。
import (
_ "gopcp.v2/helper/log/logrus"
)
这种情况下,我们只是触发了这个代码包的初始化操作,符号"_"就像一个垃圾桶。
(3)包初始化
在Go中,可以有专门的函数负责代码包初始化,成为代码包初始化函数。
这个函数无任何参数声明和结果声明,且名称必须为init。
func init() {
fmt.PrintLn("Initialize...")
}
Go会在程序真正执行前对整个程序的依赖进行分析,并初始化相关的代码包。
也就是说,所有的代码包初始化函数都会在main函数(命令源码文件的入口函数)执行前执行完毕,而且只会执行一次。
另外,对于每一个代码包来说,其中的所有全局变量的初始化,都会在代码包的初始化函数执行前完成。
这避免了在代码包初始化函数对某个变量进行赋值之后,又被该变量声明中赋予的值覆盖掉的问题
下面是一个简单示例:
//如果一个源码文件被声明属于main代码包,且该文件代码包含无参数声明和结果声明的main函数,则它就是命令源码文件。
package main //命令源码文件必须在这里声明自己属于main包
import ( //导入标准库代码包fmt和runtime
"fmt"
"runtime"
)
func init() { //代码初始化函数
fmt.Printf("Map: %v\n", m) //这里可以直接获取到变量m,可以看出变量的初始化在代码包初始化之前完成
//通过runtime获取当前操作系统和计算架构
//通过fmt的Sprintf进行格式化然后赋值给info
info = fmt.Sprintf("OS:%s,Arch:%s", runtime.GOOS, runtime.GOARCH)
} //非局部变量,map类型,且已初始化,因为已经赋值
var m = map[int]string{1: "A", 2: "B", 3: "C"}
//非局部变量,string类型,未初始化,因为还未赋值
var info string func main() { //命令源码文件必须有入口函数,也可以叫做主函数
fmt.Println(info) //代码包的初始化会在main函数执行前执行完毕
} //同一个代码包中可以存在多个代码初始化函数,甚至代码包内的每一个源码文件都可以定义多个代码初始化函数。
//Go不会保证同一个代码包中多个代码包初始化函数的执行顺序。
//被导入的代码吧的初始化函数总是会先执行,例如上面fmt和runtime中如果有init函数,那么就会先执行。
go——工程结构的更多相关文章
- Eclipse点击工程结构里任意文件或文件夹变拖动(或复制)的bug
		本文为原创文章,欢迎转载,但请注明出处http://www.cnblogs.com/yexiubiao/p/5204601.html,未在文章页面明显位置给出原文连接的,将保留追究法律责任的权利. 在 ... 
- Android开发App工程结构搭建
		本文算是一篇漫谈,谈一谈关于android开发中工程初始化的时候如何在初期我们就能搭建一个好的架构. 关于android架构,因为手机的限制,目前我觉得也确实没什么大谈特谈的,但是从开发的角 ... 
- 09-Java 工程结构管理
		(一)Java 工程结构管理 1.什么是Build Path: -- 一般包括:JRE运行时库 第三方功能扩展库(*.jar 格式文件) 其他的工程 其他的源代码或Class 文件 为什么使用~ :通 ... 
- 构建iOS稳定应用架构时方案选择的思考,主要涉及工程结构,数据流思想和代码规范
		工程结构架构,减少耦合混乱以及防治需求大改造成结构重构,如何构建稳定可扩展可变换的工程结构的思考 我打算采用Information flow的方式自上而下,两大层分为基础层和展现层的结构.基础层分为多 ... 
- iOS工程结构
		好的架构不是设计出来的,而是进化而来的! 写在前面 从2011年底开始学习iOS开发,到现在也已经快3年了,虽然中途没有一直进行iOS的开发(总是在Android和iOS间切换),但始终没 ... 
- 读阿里巴巴Java开发手册v1.2.0之工程结构有感【架构篇】
		首先,把昨天那俩条sql语句的优化原因给大家补充一下,第一条效率极低,第二条优化后的,sql语句截图如下: 经过几个高手的评论和个人的分析: 第一条sql语句查询很慢是因为它首先使用了in关键字查询, ... 
- Dubbo工程结构和Maven打包
		Dubbo 工程结构 待续 Dubbo pom版本设置 在升级Dubbo的pom版本时需要对每一个工程中子工程pom,子子工程pom进行修改,这是一个复杂繁琐的工作.为此有人手动一个个修改,好一点的用 ... 
- 【源码】otter工程结构
		最近在搞数据同步相关的内容,需要对otter的代码进行扩展,所以需要先熟悉一下otter的源码.首先我们整体来看下otter的工程结构.otter的工程结构比较复杂,需要花费一定的时间来理解各个部分的 ... 
- Spring Boot 2.x基础教程:工程结构推荐
		Spring Boot框架本身并没有对工程结构有特别的要求,但是按照最佳实践的工程结构可以帮助我们减少可能会遇见的坑,尤其是Spring包扫描机制的存在,如果您使用最佳实践的工程结构,可以免去不少特殊 ... 
- goLand工程结构管理
		goLand工程结构管理 转 https://www.jianshu.com/p/eb7b1fd7179e 开始之前请确保安装好了 go语言环境并配置好了gopath环境变量 1.创建一个新目录并打 ... 
随机推荐
- 一种480 MHz无线数传模块的设计
			一种480 MHz无线数传模块的设计 来源:电子技术应用2012年第6期 作者:严 冬,黄 聃,王 平,彭 杰,朱柏寒2012/8/13 16:56:32 关键词: 微处理器|微控制器 物联网 RF ... 
- hdu3667 Transportation 费用与流量平方成正比的最小流 拆边法+最小费用最大流
			/** 题目:hdu3667 Transportation 拆边法+最小费用最大流 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667 题意:n个城市由 ... 
- C# 路径的使用
			// 摘要: // 获取或设置包含该应用程序的目录的名称. // // 返回结果: // 应用程序基目录的名称. AppDomain.CurrentDomain.SetupInformation.Ap ... 
- 嵌入式开发之davinci--- MSB和LSB
			简介: MSB是Most Significant Bit的缩写,最高有效位.在二进制数中,MSB是最高加权位.与十进制数字中最左边的一位类似.通常,MSB位于二进制数的最左侧,LSB位于二进制数的最右 ... 
- Openstack(Kilo)安装系列之glance(六)
			安装配置 Before you install and configure the Image service, you must create a database, service credent ... 
- 深入学习QWidget-1
			1.QWidget对事件的抓取和放手.主要有例如以下几个接口 grabGesture 抓取输入手势 ungrabGesture 取消抓取手势 grabKeyboard 抓取键盘输入 grabMouse ... 
- ChemDraw Pro和ChemBio3D Ultra有什么区别
			作为ChemOffice 14的两个重要组件,ChemDraw Pro和ChemBio3D Ultra都有着自己的特点,ChemDraw Pro以绘制平面结构而ChemBio3D Ultra以绘制立体 ... 
- hdu4456 Crowd(二维树状数组)
			题意:给出一个n*n的矩阵,然后m个operation,1表示坐标(x,y)的值加z,2表示与坐标(x,y)的曼哈顿距离不超过z的点的权值和. 解题思路:将矩阵側过来45度.发现询问的时候,有效的点构 ... 
- Android开发:《Gradle Recipes for Android》阅读笔记(翻译)6.2——DSL文档
			问题: 你需要查找Android Gradle DSL的完整文档. 解决方案: 访问Gradle Tools网站,从Android开发网站下载ZIP文件. 讨论:Android开发网站首页有完整的AP ... 
- Handler用Bundle传值
			package com.handler.cn; import android.app.Activity; import android.os.Bundle; import android.os.Han ... 
