要学会两件事

  1. 封装代码函数
  2. 根据功能分模块文件工程文件的管理

如何编写go代码

代码组织

go应用使用包和模块来组织代码,包对应到文件系统就是文件夹,模块就是**xxx.go**的go源文件。一个包中会有多个模块,或者多个子包。

?go项目管理工具

早期的go项目使用gopath来管理项目,不方便而且容易出错,从golang 1.11 开始使用gomod管理项目,当然还有第三方模块例如govendor,我们给大家结束gomod的使用(知乎上有详情,稍后看看)

实现步骤

  1. 创建项目
    1. 创建项目文件夹mypro
    2. cmd定位→输入code .创建代码文件
      ?工程管理 - 图1
      ?工程管理 - 图2
  2. 初始化项目
    go mod init mypro(项目名称)执行之后会生成go.mod文件
    ?工程管理 - 图3
  3. 创建包→创建模块
    1. 新建文件夹user,创建user.go模块,写入一些东西,package xxx与包同名
      ?工程管理 - 图4
    2. 创建main.go模块,main主包下的main函数是项目的入口
      ?工程管理 - 图5
  4. 相互调用
    引入包→调用
    ?工程管理 - 图6

包的意义就在于避免重复写代码,一个文件夹,就是一个包;Go语言是通过包来管理文件的

基本知识

包的概念

  1. 什么是包?
    1. 包(package)是多个Go源码的集合, 是一种高级的代码复用方案
    2. 一个文件夹 = 一个包,还要子包;一个文件=一个模块
    3. 一个包的源代码保存在一个或多个以.go为文件后缀名的源文件中,通常一个包所在目录路径的后缀是包的导入路径。
  2. 要求
  3. 什么是包内包外?
    ——同一包声明,就是包内 = 同一文件夹下;包外,就是不同文件夹之间

包的作用

  1. 内置包
    ——Go语言为我们提供了很多内置包,如fmtosio等,可以现成直接import 获得使用
  2. 当程序文件很多的时候,可以很好地管理项目,相当于创建了共享中心
    ——通过import"B"可以调用在A中,使用B包中定义的函数/方法等等
  3. 区分相同名字的函数、变量等标识符
    ——解释:同一个包下,函数名具有唯一性,不同包下可以声明定义名字相同的两个函数
  4. 控制函数、变量等访问范围,即作用域

包的要求

  • 同一个包(文件夹)下,所有go文件都只能用同一个package,也就是每个文件开头的package 后面的名字要一致。
    • 只有两种情况:
使用场景
package main 含有main函数的主文件
package 文件夹名(不是文件名) 不含main函数但是可含init函数的文件夹内的文件
  1. + import后面的其实是GOPATH开始的相对目录路径,包括最后一段。但由于一个目录下只能有一个package,所以import一个路径就等于是import了这个路径下的包。(现在用gomod就不太用这个)
  2. + 注意,这里指的是"直接包含”的go文件。如果有子目录,<font style="color:#E8323C;">那么子目录的父目录是完全两个包。</font>
  • 实例
    ——比如你实现了一个计算器package,名叫calc,位于calc目录下;仅想给别人一个使用范例,于是在calc下可以建个example子目眼(calc/example/),这个子 目录里有个example.go (calc/example/example.go) 。此时,example.go可以是main包, 里面还可以有个main函数。
  • 重名问题
    ——解决方法:起别名
    ?工程管理 - 图7

语法

如何创建包?

:::info 前言:包要在环境变量里

:::

  1. 以前,对于一个较大的应用程序,我们应该将它的功能性分隔成逻辑的单元,分别在不同的包里实现。我们创建的的自定义包最好放在GOPATH的src目录下(或者GOPATH src的某个子目录)。
  2. 现在多用gomod

:::info 步骤

:::

  1. 创建文件夹/包
  2. 创建一个xxx.go文件
  3. package xxx
    1. 代码包中的源码文件名可以是任意的。但是,第一行必须是package xxx,声明该文件归属的包
    2. pakage main 或者package calc(文件夹名)

引入包

以前,引入的包,也要保证在环境变量里,现在用gomod管理

语法import "xxx"

  1. //方式1
  2. import "fmt"
  3. import "os"
  4. //方式2,最常用
  5. import (
  6. "fmt"
  7. "os"
  8. )
  9. //方式3:(.)点操作,下面操作无需 包.函数/方法,直接写函数和方法
  10. import . "fmt"
  11. func main{
  12. Println("on testing")//好处是简约了一些
  13. Println("os,Args = ", Args)
  14. //坏处是当包很多的时候,一旦变量名与包重名,或者包重名,程序就会崩
  15. }

方式4:地址

包名是从$GOPATH/src/后开始计算的,使用/进行路径分隔

实例:

?工程管理 - 图8

?工程管理 - 图9

:::info 给包起别名

:::

?工程管理 - 图10

目的:避免包的同名冲突,或者是包名比较长,不好调用

注意:包名不可重复

:::info 忽略此包

:::

我们知道引入了包不用,是会把报错的,那么怎么在不删除引入包命令的条件下,不报错呢?

import _ "B"

更重要的是,可以用此命令只引入并执行该包中的init函数,而不使用该包中的其他定义好的函数

调用包

  • 语法:包.xxx
  • 函数可见性
    • public:首字母大写,可被包外访问
    • private:首字母小写,仅包内成员可以访问

?包管理工具 go module

go module是go 1.11后的新加的特性,用来管理包的依赖关系,简称go mod,网站最详细教程

go mod使用方法

最常用,就开头两个

  • 初始化模块
    go mod init <项目模块名称>
  • 依赖关系处理,根据go.mod文件
    go mod tidy
  • 将依赖包赋值到项目下的vendor目录
    go mod vendor
    如果包被屏蔽(墙),可以使用这个命令,随后使用 go build -mod=vendor编译
  • 显示依赖关系
    go list -m all
  • 显示详细依赖关系
    go list -m -json all
  • 下载依赖
    go mod download [path@version]
    [path@version]是非必写的

实例

:::info 自建包然后引用

:::

  1. step_1
    1. 新建文件pro02,创建代码
    2. 在终端,初始化模块go mod init duoke360.com/pro02域名duoke360.com是什么???
  2. step_2
    1. 新建main.go文件,新建service包,分别写入内容
      ?工程管理 - 图11
    2. 终端转移到该目录下cd .\service\
    3. 编译go build
      ?工程管理 - 图12
  3. step_3
    1. 在main文件内,引入import "duoke360.com/pro02/service"
    2. 即可调用包内函数 service.<函数/方法>

:::info 引入远程包

:::

  1. 寻找下载地址
    ?工程管理 - 图13
    找gin包
    ?工程管理 - 图14
  2. 下载go get <网址> -u是什么???
    ?工程管理 - 图15
  3. 即可引用,引入语法网址提供
    ?工程管理 - 图16

main函数

:::info main特点

:::

  1. 无参数、无返回值
  2. main函数必须要在main包里
    ?工程管理 - 图17
  3. 可执行程序内必须有,且仅有一个main的包
  4. 应用程序入口
    1. 必须是main包
    2. 必须是main方法
    3. 文件名不一定是main.go

原理解读:
在Go语言里,命名为main的包具有特殊的含义。Go语言的编译程序会试图把这种名字

的包编译为二进制可执行文件。所有用Go语言编译的可执行程序都必须有一个名叫main

的包。一个可执行程序有且仅有一个main包。

当编译器发现某个包的名字为main时,它一 定也会发现名为main()的函数,否则不会创

建可执行文件。main() 函数是程序的入口,所以,如果没有这个函数,程序就没有办法开

始执行。程序编译时,会使用声明main 包的代码所在的目录的目录名作为二进制可执行文

件的文件名。

思考:

由于main函数在可执行程序里的唯一性与必要性,包可分为有main函数的,和没有main函数的

  1. 有main函数的必定可划分为执行程序,且开头必然是 package main,
  2. 无main函数的,只能是引用,开头可以是 package xxx文件夹名

环境变量

环境变量是什么?

  1. 作用:
    环境变量的作用就是,指明操作系统的重要目录在哪里
  2. systemroot——环境变量
    程序在运行时需要从系统目录读取文件,你说它是在磁盘上挨个找这个目录呢?还是让操作系统告诉他目录——显然后者更高效快捷,故用systemRoot来指明系统目录所在的位置,这就是所谓的环境变量
    ?工程管理 - 图18
    ?工程管理 - 图19
    <font style="color:#DF2A3F;">%xxx%</font>表示的就是某环境变量
    ➡windows系统目录
    ?工程管理 - 图20
  3. Windows中常见的环境变量有
  • %SYSTEMROOT%:操作系统的根目录,通常是 C:\Windows。
  • %WINDIR%:同 %SYSTEMROOT%,指向操作系统的根目录。
  • %SYSTEMDRIVE%:系统所在的驱动器,通常是 C:。
  • %HOMEDRIVE%:用户主目录所在的驱动器,通常是 C:。
  • %HOMEPATH%:用户主目录的路径,通常是 \Users{用户名}。
  • %USERPROFILE%:当前用户的配置文件目录,通常是 C:\Users{用户名}。
  • %APPDATA%:当前用户的应用程序数据文件夹路径,通常是 C:\Users{用户名}\AppData\Roaming。
  • %LOCALAPPDATA%:当前用户的本地应用程序数据文件夹路径,通常是 C:\Users{用户名}\AppData\Local。
  • %TEMP%****%TMP%:当前用户的临时文件夹路径,通常是 C:\Users{用户名}\AppData\Local\Temp。
  • %PROGRAMFILES%:系统的程序文件夹路径,通常是 C:\Program Files。
  • %PROGRAMFILES(X86)%:在64位系统上,用于存放32位程序的文件夹路径,通常是 C:\Program Files (x86)。
  • %COMMONPROGRAMFILES%:程序文件的公共文件夹路径,通常是 C:\Program Files\Common Files。
  • %COMMONPROGRAMFILES(X86)%:在64位系统上,32位程序的公共文件夹路径,通常是 C:\Program Files (x86)\Common Files。
  • %PATH%:可执行文件的搜索路径。多个路径使用分号分隔。
  • %PATHEXT%:系统可识别的可执行文件扩展名列表。
  • %COMSPEC%:命令处理器的路径,通常是 C:\Windows\System32\cmd.exe。
  • %NUMBER_OF_PROCESSORS%:计算机中的处理器数量。
  • %PROCESSOR_ARCHITECTURE%:处理器架构类型,例如 AMD64 或 x86。
  • %PROCESSOR_IDENTIFIER%:处理器的描述字符串。
  • %ALLUSERSPROFILE%:所有用户的公共配置文件目录,通常是 C:\ProgramData。
  • %PUBLIC%:公共用户文件夹,通常是 C:\Users\Public。

分类

  1. 分为系统变量和用户变量
  2. 区别
    环境变量是root的环境变量,作用于所有用户;用户环境变量,仅作用于当前电脑系统登录的账户
    (也就是说如果你电脑账户只有一个,那就无所谓)

怎么用?

PATH和编程息息相关的环境变量

  1. 系统会尝试在Path指明的目录中查找cmd这个程序,找到就运行,找不到就报错
    ?工程管理 - 图21
    之所以能运行是因为Path环境变量有cmd所在的地址
    ?工程管理 - 图22
    ?工程管理 - 图23
  2. 如果我们要在dos上运行一个程序,那怎么办呢?
    1. 把文件放到系统目录下
    2. 环境变量里添加新地址(要运行的程序所在的地址)

GO实际运用

  1. goland软件支持为项目独立设置环境变量,教程
  2. GOPATH环境变量默认为go语言安装的位置,可修改,貌似Path也添加了
  3. goroot就是go安装的根目录, gopath就是go项目所在的路径, 高版本go项目已经不再依赖gopath来管理项目,使用go mod来管理项目。

?创建文件步骤

问题

  1. 创建新模块,包如何声明?
  2. 环境变量需要创建吗?
    1. gopath
      1. 系统里path的设置,问,GOPATH和PATH里的什么关系???
      2. goland软件支持为项目独立设置环境变量
    2. gomod???
    3. 第三方管理软件
  3. 需要引入包吗?
    1. 同一个包内需要引用,不同包内无需引用
    2. 引用语法
  4. 调用时候,包名.xxx且要求函数/方法/变量…必须大写

工作区

Go代码必须放在工作区中。工作区其实就是一个对应于特定工程的目录,它应包含3个子 目录: src目录、pkg目录和bin目录。 + src目录:用于以代码包的形式组织并保存Go源码文件。(比如: .go.c.h.s等) + pkg目录:用于存放经由go install命令构建安装后的代码包(包含Go库源码文件)的“.a”归档文件。 + bin目录:与pkg目录类似,在通过go install命令完成安装后,保存由Go命令源码文件生成的可执行文件。(exe?)
简化:
?工程管理 - 图24 目录src用于包含所有的源代码,是Go命令行工具一个强制的规则,必须有,而pkg和bin则无需 手动创建,如果必要Go命令行工具在构建过程中会自动创建这些目录。 需要特别注意的是,只有当环境变量GOPATH中只包含一个工作区的目录路径时,goinstall 命令才会把命令源码安装到当前工作区的bin目录下。若环境变量GOPATH中包含多个工 作区的目录路径,像这样执行go install命令就会失效,此时必须设置环境变量GOBIN。

同一目录

  1. 创建src文件夹
    分文件编程(多个源文件),必须放在src目录,即我们创建一个src文件夹,等会在里面创建文件
  2. 设置GOPATH环境变量
    注意是src所在地地址,不要进去src,据我所知,有两种方式
    1. 一种是在我的电脑的高级系统设置里,修改环境变量(在DOS窗口输入 go env 可查看相关的环境变量地设置)
    2. 一种是用IDE,我用的GOPATH可以为每个工程设置单独的环境变量
  3. 创建文件
    1. 同一个目录下,包名必须一致
    2. 同一个目录下,调用别的文件的函数,直接调用,无需引入包名(实例中,可在main函数下,直接引用test)
    3. main函数必须有,又必须在package main之下,故主文件,其实必然是package main开头
      什么情况是package xxx文件夹名的?看下方的不同目录情况

:::info 画图实例展示

:::

?工程管理 - 图25

不同目录

  1. 创建文件夹和写package xxx
    在src下,创建别的文件夹,不同目录,包名可以不是main,但需要和文件夹名统一(package xxx文件夹名的
  2. 环境变量配置
    创建了新的文件夹之后,同样要设置环境变量,在IDE里设置即可(???若在环境变量里,创建文件夹,需要重新再设环境变量吗?)
  3. 要在A包中引入B包的函数Add
    1. 此函数必须大写开头 Add
    2. 代码开头 package "A"+ 代码过程 A.Add(...)
      (有的时候,要go build 一下B包,产生可执行文件.exe,才能在A包中显现/提示出来)

:::info 实例

:::

?工程管理 - 图26

src文件夹下

?工程管理 - 图27

main.go文件

?工程管理 - 图28

calc.go文件

?工程管理 - 图29

文件执行步骤

文件执行步骤

?工程管理 - 图30

init函数作用:

  1. 引入别的包,该包中,若自定义的函数没被引用,是不会执行的,所以诞生了init函数,只要导入B包,B包的init函数就会执行
  2. 若主文件,本身也有init函数,那么也会比main函数先执行
  3. import _ "A"实际是引入该包,不使用包里的函数,而是调用了包里的init函数

init 函数

先看完下面的文件创建步骤,再看这个init包

go语言中init函数用于包(package)的初始化,该函数是go语言的一个重要特性。 有下面的特征:
  1. 作用
    init函数是用于程序执行前做包的初始化的函数,比如初始化包里的变量等
  2. 要求
    1. 每个包可以拥有多个init函数
    2. 包的每个源文件也可以拥有多个init函数
    3. init函数不能被其他函数调用,而是在main函数执行之前,自动被调用
  3. 执行顺序
    1. 同一个包中多个init函数的执行顺序go语言没有明确的定义(说明)
    2. 不同包的init函数按照包导入的依赖关系决定该初始化函数的执行顺序

init函数和main函数的异同

相同点:两个函数在定义时不能有任何的参数和返回值,且Go程序自动调用。

不同点:

init可以应用于任意包中,且可以重复定义多个。

main函数只能用于main包中,且只能定义一个。

:::info 两个函数的执行顺序

:::

  1. 对同一个go文件
    init()调用顺序是从上到下的。
  2. 对同一个package中不同文件
    是按文件名字符串比较“从小到大”顺序调用各文件中的init()函数。
  3. 对于不同的package 1. 如果不相互依赖的话,按照main包中”先import的后调用”的顺序调用其包中的init() 2. 如果package存在依赖,则先调用最早被依赖的package中的init(),最后调用main函数。
  4. 如果init函数中使用了println()或者print()
    你会发现在执行过程中这两个不会按照你想象中的顺序执行。这两个函数官方只推荐在测试环境中使用,对于正式环境不要使用。

常用命令

?工程管理 - 图31?工程管理 - 图32

:::info 最常用:

:::

  1. go build xxx编译包和依赖
    go build xxx + ./xxx(可执行文件)
    ?工程管理 - 图33
  2. go run xxx运行
  3. go env xxx 显示当前go的环境的信息
  4. go get
    1. 找到项目
      ?工程管理 - 图34
    2. go mod init 项目名称???
    3. go get xxx
      ?工程管理 - 图35
  5. go list列出包

git

版本管理,主要用于github上下载非常方便,git clone ...

?工程管理 - 图36

?工程管理 - 图37

?power shell