一、概述

  Golang拥有超过100个标准包(可用go list std |wc -l查看)

  任何包系统设计的目的都是简化大型程序的设计和维护工作,通过将一组相关的特性放进一个独立的模块以便于理解和更新,在每个模块更新的同时保持和程序中其他模块的相对独立,这种模块化的特性允许每个包能被其他的不同项目共享和重用,在项目范围内、全局范围内的复用;

  每个包一般都定义了一个不同的名字空间用于它内部的每个标识符的访问。 每个名字空间关联到一个特定的包, 让我们给类型、 函数等选择简短明了的名字, 这样可以避免在我们使用它们的时候减少和其它部分名字的冲突。

  每个包还通过控制包内名字的可见性和是否导出来实现封装特性。 通过限制包成员的可见性并隐藏包API的具体实现, 将允许包的维护者在不影响外部包用户的前提下调整包的内部实现。 通过限制包内变量的可见性, 还可以强制用户通过某些特定函数来访问和更新内部变量, 这样可以保证

内部变量的一致性和并发时的互斥约束。

二、包的使用之导入路径

  每个包是由一个全局唯一的字符串所标识的导入路径定位。 出现在import语句中的导入路径也是字符串。

import (
"fmt"
"math/rand"
"encoding/json"
"golang.org/x/net/html"
"github.com/go-sql-driver/mysql"
)

三、包声明:

  在每个Go源文件的开头都必须有包声明语句。 包声明语句的主要目的是确定当前包被其它包导入时默认的标识符(也称为包名)

  例如, math/rand包的每个源文件的开头都包含 package rand 包声明语句, 所以当你导入这个包, 你就可以用rand.Int、 rand.Float64类似的方式访问包的成员。

  关于默认包名一般采用导入路径名的最后一段的约定也有三种例外情况。

    第一个例外, 包对应一个可执行程序, 也就是main包, 这时候main包本身的导入路径是无关紧要的。 名字为main的包是给go build( §10.7.3) 构建命令一个信息, 这个包编译完之后必须调用连接器生成一个可执行程序。

    第二个例外, 包所在的目录中可能有一些文件名是以test.go为后缀的Go源文件( 译注:前面必须有其它的字符, 因为以``前缀的源文件是被忽略的) , 并且这些源文件声明的包名也是以_test为后缀名的。 这种目录可以包含两种包:一种普通包, 加一种则是测试的外部扩展包。

  所有以_test为后缀包名的测试外部扩展包都由go test命令独立编译, 普通包和测试的外部扩展包是相互独立的。 测试的外部扩展包一般用来避免测试代码中的循环导入依赖。

    第三个例外, 一些依赖版本号的管理工具会在导入路径后追加版本号信息, 例如"gopkg.in/yaml.v2"。 这种情况下包的名字并不包含版本号后缀, 而是yaml。  

   warning:如果我们想同时导入两个有着名字相同的包, 例如math/rand包和crypto/rand包, 那么导入声明必须至少为一个同名包指定一个新的包名以避免冲突。 这叫做导入包的重命名。

    import (
      "crypto/rand"
      mrand "math/rand"   // alternative name mrand avoids conflict
    )

  warning:匿名导入:

    import _ "image/png" // register PNG decoder

 // The jpeg command reads a PNG image from the standard input
// and writes it as a JPEG image to the standard output.
package main
import (
  "fmt"
  "image"
  "image/jpeg"
  _ "image/png" // register PNG decoder
  "io"
  "os"
)
func main() {
  if err := toJPEG(os.Stdin, os.Stdout); err != nil {
    fmt.Fprintf(os.Stderr, "jpeg: %v\n", err)
    os.Exit(1)
  }
}
func toJPEG(in io.Reader, out io.Writer) error {
  img, kind, err := image.Decode(in) //这里可能需要匿名导入
  if err != nil {
    return err
  }
  fmt.Fprintln(os.Stderr, "Input format =", kind)
  return jpeg.Encode(out, img, &jpeg.Options{Quality: 95})
}

  下面说说工作机制。 标准库还提供了GIF、 PNG和JPEG等格式图像的解码器,用户也可以提供自己的解码器, 但是为了保持程序体积较小, 很多解码器并没有被全部包含, 除非是明确需要支持的格式。 image.Decode函数在解码时会依次查询支持的格式列表。

  每个格式驱动列表的每个入口指定了四件事情:格式的名称;一个用于描述这种图像数据开头部分模式的字符串, 用于解码器检测识别;一个Decode函数用于完成解码图像工作;一个DecodeConfig函数用于解码图像的大小和颜色空间的信息。 每个驱动入口是通过调用image.RegisterFormat函数注册, 一般是在每个格式包的init初始化函数中调用, 例如image/png包是这样注册的:

 package png // image/png
func Decode(r io.Reader) (image.Image, error)
func DecodeConfig(r io.Reader) (image.Config, error)
func init() {
  const pngHeader = "\x89PNG\r\n\x1a\n"
  image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
}

  最终的效果是, 主程序只需要匿名导入特定图像驱动包就可以用image.Decode解码对应格式的图像!

四、自定义自己的包:

  包是函数和数据的集合。用 package 关键字定义一个包。文件名不需要与包名一致,但是你的文件夹必须要与包名字一致,这个很重要,所以为了简单起见,名字都是一样的。包名的约定是使用小写字符。Go 包可以由多个文件组成,但是使用相同的;
  package 这一行。让我们在文件 test1.go 中定义一个叫做 pkg的包。

 ├── pkg
│   └── myprint.go //myprint.go
package pkg
import "fmt"
func MyPrintf(in string) {
fmt.Printf("%s", in)
}

  在main包中测试:

 package main
import (
"fmt"
"./pkg" //带上路径
) func main() {
pkg.MyPrinf("my pkg test")
fmt.Printf("test ok")
} //测试ok
稍作修改:
package main
import (
"fmt"
"pkg" //不带上路径
) func main() {
pkg.MyPrinf("my pkg test")
fmt.Printf("test ok")
} //closure.go:6:2: cannot find package "pkg" in any of:
/root/golang/go/src/pkg (from $GOROOT)
/root/src/pkg (from $GOPATH) # 解决办法:将pkg包加个软连接到$GOROOT 或$GOPATH

最新文章

  1. Activity has leaked window that was originally added -界面退出时未关闭对话框异常 android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? -
  2. MySQL中文全文检索
  3. LR Socket 测试demo
  4. zw版【转发·台湾nvp系列Delphi例程】HALCON HWindowX 02
  5. 清除IE中Ajax缓存,Chrome不需要
  6. 简单的实现树莓派的WEB控制
  7. Spring Boot 系列教程2-Data JPA
  8. Python实战之双向队列deque/queue学习笔记及简单练习
  9. c#位运算基本概念与计算过程
  10. kubernetes系列06—kubernetes资源清单定义入门
  11. MySQL 笔记整理(1) --基础架构,一条SQL查询语句如何执行
  12. java通过Access_JDBC30读取access数据库时无法获取最新插入的记录
  13. valgrind 开发板调试
  14. 深探树形dp
  15. Windows 8.1 GetVersionEx返回6.2.9200 的问题!
  16. iqueryable lambda表达式
  17. EXP-00056:遇到oracle错误12154
  18. 交叉编译OpenCV的Android版本
  19. ( VIJOS )VOJ 1049 送给圣诞夜的礼品 矩阵快速幂
  20. 6.centos7 gitblit

热门文章

  1. java中a++与++a区别
  2. Young Table(暴力,交换位置)
  3. UVa 1394: And Then There Was One
  4. andorid 控件 Bootstrap3.0风格的控件 精美UI控件库
  5. Java中的内存泄漏问题
  6. python3 module中__init__.py的需要注意的地方
  7. onvif规范的实现:成功实现ONVIF协议RTSP-Video-Stream与OnvifDeviceManager的视频对接
  8. Node.js实践第一天
  9. iframe 重新加载闪过白块问题
  10. js 去掉空格