import导入包

搜索路径

import用于导入包:

import (
"fmt"
"net/http"
"mypkg"
)

编译器会根据上面指定的相对路径去搜索包然后导入,这个相对路径是从GOROOT或GOPATH(workspace)下的src下开始搜索的。

假如go的安装目录为/usr/local/go,也就是说GOROOT=/usr/local/go,而GOPATH环境变量GOPATH=~/mycode:~/mylib,那么要搜索net/http包的时候,将按照如下顺序进行搜索:

/usr/local/go/srcnet/http
~/mycode/src/net/http
~/mylib/src/net/http

以下是go install搜索不到mypkg包时的一个报错信息:

can't load package: package mypkg: cannot find package "mypkg" in any of:
/usr/lib/go-1.6/src/mypkg (from $GOROOT)
/golang/src/mypkg (from $GOPATH)

也就是说,go总是先从GOROOT出先搜索,再从GOPATH列出的路径顺序中搜索,只要一搜索到合适的包就理解停止。当搜索完了仍搜索不到包时,将报错。

包导入后,就可以使用这个包中的属性。使用包名.属性的方式即可。例如,调用fmt包中的Println函数fmt.Println

包导入的过程

首先从main包开始,如果main包中有import语句,则会导入这些包,如果要导入的这些包又有要导入的包,则继续先导入所依赖的包。重复的包只会导入一次,就像很多包都要导入fmt包一样,但它只会导入一次。

每个被导入的包在导入之后,都会先将包的可导出函数(大写字母开头)、包变量、包常量等声明并初始化完成,然后如果这个包中定义了init()函数,则自动调用init()函数。init()函数调用完成后,才回到导入者所在的包。同理,这个导入者所在包也一样的处理逻辑,声明并初始化包变量、包常量等,再调用init()函数(如果有的话),依次类推,直到回到main包,main包也将初始化包常量、包变量、函数,然后调用init()函数,调用完init()后,调用main函数,于是开始进入主程序的执行逻辑。

别名导入和特殊的导入方法

当要导入的包重名时会如何?例如network/convert包用于转换从网络上读取的数据,file/convert包用于转换从文件中读取的数据,如果要同时导入它们,当引用的时候指定convert.FUNC(),这个convert到底是哪个包?

可以为导入的包添加一个名称属性,为包设置一个别名。例如,除了导入标准库的fmt包外,自己还定义了一个mypkg/fmt包,那么可以如下导入:

package main

import (
"fmt"
myfmt "mypkg/fmt"
) func main() {
fmt.Println()
myfmt.myfunc() // 使用别名进行访问
}

如果不想在访问包属性的时候加上包名,则import导入的时候,可以为其设置特殊的别名:点(.)。

import (
. "fmt"
) func main() {
Println() // 无需包名,直接访问Println
}

这时要访问fmt中的属性,必须不能使用包名fmt。

go要求import导入的包必须在后续中使用,否则会报错。如果想要避免这个错误,可以在包的前面加上下划线:

import (
"fmt"
_ "net/http"
"mypkg"
)

这样在当前包中就无需使用net/http包。其实这也是为包进行命名,只不过命名为"_",而这个符号又正好表示丢弃赋值结果,使得这成为一个匿名包。

下划线(_)

在go中,下划线出现的频率非常高,它被称为blank identifier,可以用于赋值时丢弃值,可以用于保留import时的包,还可以用于丢弃函数的返回值。详细内容可参见官方手册:https://golang.org/doc/effective_go.html#blank

导入而不使用看上去有点多此一举,但并非如此。因为导入匿名包仅仅表示无法再访问其内的属性。但导入这个匿名包的时候,会进行一些初始化操作(例如init()函数),如果这个初始化操作会影响当前包,那么这个匿名导入就是有意义的。

远程包

现在通过分布式版本控制系统进行代码共享是一种大趋势。go集成了从gti上获取远程代码的能力。

例如:

$ go get github.com/golang/example

在import语句中也可以使用,首先从GOPATH中搜索路径,显然这是一个URL路径,于是调用go get进行fetch,然后导入。

import (
"fmt"
"github.com/golang/example"
)

当需要从git上获取代码的时候,将调用go get工具自动进行fetch、build、install。如果workspace中已经有这个包,那么将只进行最后的install阶段,如果没有这个包,将保存到GOPATH的第一个路径中,并build、install。

go get是递归的,所以可以直接fetch整个代码树。

常量和变量的初始化

Go中的常量在编译期间就会创建好,即使是那些定义为函数的本地常量也如此。常量只允许是数值、字符(runes)、字符串或布尔值。

由于编译期间的限制,定义它们的表达式必须是编译器可评估的常量表达式(constant expression)。例如,1<<3是一个常量表达式,而math.Sin(math.Pi/4)则不是常量表达式,因为涉及了函数math.Sin()的调用过程,而函数调用是在运行期间进行的。

变量的初始化和常量的初始化差不多,但初始化的变量允许是"需要在执行期间计算的一般表达式"。例如:

var (
home = os.Getenv("HOME")
user = os.Getenv("USER")
gopath = os.Getenv("GOPATH")
)

init()函数

Go中除了保留了main()函数,还保留了一个init()函数,这两个函数都不能有任何参数和返回值。它们都是在特定的时候自动调用的,无需我们手动去执行。

还是这张图:

每个包中都可以定义init函数,甚至可以定义多个,但建议每个包只定义一个。每次导入包的时候,在导入完成后,且变量、常量等声明并初始化完成后,将会调用这个包中的init()函数。

对于main包,如果main包也定义了init(),那么它会在main()函数之前执行。当main包中的init()执行完之后,就会立即执行main()函数,然后进入主程序。

所以,init()经常用来初始化环境、安装包或其他需要在程序启动之前先执行的操作。如果import导入包的时候,发现前面命名为下划线_了,一般就说明所导入的这个包有init()函数,且导入的这个包除了init()函数外,没有其它作用。

Go基础系列:import导包和初始化阶段的更多相关文章

  1. Python 基础之import导包

    首先需要将import内容建立一个大概如下层级的包: 以黑色框为第一级,蓝色框为第二级,棕色框为第三级,红色框为第四级 一.import 引入初识 首先在module.py写入代码如下: xboy = ...

  2. 【python3】 解:import导包机制

    模块和包 模块:我们定义的.py结尾的文件就是一个模块,模块中通常定义了类.方法.变量等一系列功能: 包:存放模块的文件夹,含有init.py文件,定义path属性. import语句的作用 impo ...

  3. import 导包三种方法

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #导包三种方法 #(常用)完整的导入,也是最基本的方法 import re #自己定义别名,一般情况下尽量少用 ...

  4. openresty开发系列32--openresty执行流程之1初始化阶段

    openresty开发系列32--openresty执行流程之初始化阶段 一)初始化阶段 1)init_by_lua   init_by_lua_block     init_by_lua_file语 ...

  5. opencv——import导包出现错误

    原因:编辑器找不到,CV2的模块,也就是导入这个模块失败: 原因可能是sublime找不到这个这个模块的位置,不知道这个包在哪里,这时候需要我们安装OpenCV的一个扩展包. 解决步骤: ①:找到py ...

  6. python导包学习总结

    python初学者,对于导包纠结了不少时间,总结分享,持续前进~ Python导包的两种方法: 1.1  from 包.模块  import 方法名,调用时直接使用方法名() 1.2  from 包. ...

  7. 夯实Java基础系列5:Java文件和Java包结构

    目录 Java中的包概念 包的作用 package 的目录结构 设置 CLASSPATH 系统变量 常用jar包 java软件包的类型 dt.jar rt.jar *.java文件的奥秘 *.Java ...

  8. Intellij Idea系列之导Jar包与编写单元测试(二)

     Intellij Idea系列之导Jar包与编写单元测试(二) 一.初衷 对于很多的初学者来说,Intellij如何导入jar包感到很迷惑,甚至在网上搜过相关文章之后还是云里雾里,本博客通过图文并茂 ...

  9. JAVA_SE基础——57.有了包之后类与类之间的访问使用import语句

    代码1访问代码2 代码1: class Demo3 { public static void main(String[] args) { Demo4 a = new Demo4(); a.print( ...

随机推荐

  1. docker + mysql安装sonarqube

    docker sonarqube地址:https://hub.docker.com/_/sonarqube docker mysql地址:https://hub.docker.com/_/mysql ...

  2. 学习笔记day1-计算机介绍

    1.1 “计算机”基本介绍 一.为什么需要计算机 对于现在的我们来说,每天要处理的信息量是巨大的,所以如果还是人工的来对这些数据进行处理,那么效率是很低的.此时计算机的出现就可以帮助我么来提高处理数据 ...

  3. ffmpeg源码编译安装(Compile ffmpeg with source) Part 1 : 通用部分

    本页内容包含了在Unix/Linux中用源码包编译的通用的结构 可能不仅仅适用于ffmpeg 为啥使用源码包编译 编译源码可以扩展功能, 实现相对于自己平台的最优化, 还可以自定义的修改 概述 大部分 ...

  4. 中触发一个断点 其原因可能是堆被损坏,这说明 ***.exe 中或它所加载的任何 DLL 中有 Bug

    软件中使用了DevComponents.DotNetBar2.dll MessageBoxEx.Show("ddd");运行到这句出现这个错误 : 中触发一个断点 其原因可能是堆被 ...

  5. 利用 awk 统计nginx 中某一个用户的访问次数

    线上总是会遇到攻击,所以就需要分析 access.log 看看那些用户的访问次数不正常,针对这些不正常的用户,要做处理,以 access.log为例说明下怎么统计. 通过 access.log 日志来 ...

  6. Pip无法卸载某些包:Cannot uninstall 'PyYAML'.

    查找了很多资料,最终还是手动删除吧: 注意如果你有火萤酱或everything等外部索引的,来搜索如图PyYAML的进行删除,可能删不干净 建议最后在你的anaconda路径下或者python路径下在 ...

  7. Python基础理论 - 面向对象

    一 面向对象基本理论 面向过程:核心是过程,过程就是解决问题的步骤,即先干什么,再干什么 基于面向过程设计程序,就好比在设计一条流水线,是一种机械思维方法 优点:复杂的问题简单化 缺点:可扩展性差(牵 ...

  8. JAVA RSA加密AES加密

    RSA加密: import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import javax.crypto.Cipher; imp ...

  9. 工作了才发现display全忘了

    CSS display属性这几天用的我头疼 人老了 健忘了 1.inline(行内元素) 是元素变成行内元素,拥有行内元素特性,共享属性,不会吃独食! 共享经济时代 inline是主导大哥 !impo ...

  10. Vue过渡mode属性踩坑

    近期学习Vue的过渡效果的时候,mode属性的"in-out"."out-in"设置了不起作用,官网上的例子让我看了有点迷,问题解决后以此文记录之. 首先我们看 ...