Go学习-Go基本语法
包
在 Go 语言中,包(Package) 是最基础的代码组织单位
包的基本概念
Go 程序是由一个个“包”组成的。每个 Go 源文件的第一行非注释代码必须是:
1 | package name |
- 一个文件夹就是一个包
- 同一个文件夹下的所有
.go文件必须声明相同的包名(通常包名与文件夹名一致,但不是强制的,建议保持一致)。
包的作用
- 将复杂的程序拆分成小的、易于管理的单元。
- 通过包来控制哪些函数或变量是外部可见的。
- 通过包名(如
fmt.Printf和log.Printf)进行区分,避免命名冲突。
包的可见性控制
包内共享所有变量,常量,以及所有定义的类型,但对于包外而言并不是这样,有时候你并不想让别人访问某一个类型,所以就需要控制可见性。不同于其他的OOP语言存在public和pravite关键词,Go语言控制可见性仅需设置名称的大小写来实现:
- 以大写字母开头,那么它可以被包外的代码访问(相当于 Public)。
- 以小写字母开头,则只能在包内部使用(相当于 Private)。
包的导入
导入一个包的变量,类型,方法,函数等,使用import关键词
导入一个包
1
2
3package main
import "example"导入多个包
1
2
3
4package main
import "example1"
import "example2"或者:
1
2
3
4
5
6package main
import (
"example1"
"example2"
)导入重名包/包名复杂
可以使用别名来起别名:
1
2
3
4
5
6package main
import (
e1 "example1"
e2 "example2"
)匿名导入包
匿名导入的包无法被使用,这么做通常是为了加载包下的
init函数,但又不需要用到包中的类型,一个常见的例子就是注册数据库驱动,但是你并不需要去手动使用驱动。1
2
3
4
5
6package main
import (
e "example"
_ "mysql-driver-go"
)特殊的导入包格式
将该包中的所有类型都导入到当前包作用域,以这种方法导入的类型不再需要
.运算符去访问,但是如果有重名的类型将会无法通过编译。1
2
3
4
5package main
import (
. "example"
)
注意:包不能循环导入或者相互导入
内部包
内部包(Internal Packages) 是一种特殊的访问控制机制。它允许你在一个项目中跨目录共享代码,但禁止外部项目引用这些代码
为什么需要 Internal 包?
假设你正在开发一个大型开源库。你有一些复杂的逻辑需要分成好几个子包(文件夹)来组织,但你并不希望这些复杂的底层逻辑被外部用户直接调用。如果你把函数首字母大写,外部用户就能看到并依赖它们;一旦你未来想修改这些底层逻辑,就会破坏外部用户的代码(破坏兼容性)。
举一个例子,你在开发一个开源的购物系统,你的项目包含api(用来外部用户调用)crypto(用来加密订单信息)
文件结构如下所示:
1 | Shop/ |
如果没有 Internal 包
你为了
api包中能调用crypto中的Encrypt(),你必须把这个函数首字母大写布豪的事情发生了:
任何下载了你这个库的人,不仅可以使用
api.OrderGood()(order中的方法),还可以直接在他们的代码里写:import "github.com/yourname/Shop/crypto"它可以直接绕过你的api直接调用加密算法!你会遇到以下麻烦:
不敢随便改代码:三个月后,你发现
Encrypt()有漏洞,你想把Encrypt(data string)改成Encrypt(data string, salt string)。被迫背锅:你一改,全世界成千上万个直接用了你
crypto包的开发者代码都会编译报错。你很冤枉:你本意是这个加密函数只给自己的
api包内部使用,根本没想过让别人用。但因为你要跨包(从api到crypto),你不得不把它公开。所以我们引入Internal 包
现在你引入了 Internal 包
将文件结构修改成:
1
2
3
4
5
6Shop/
├── api/
│ └── order.go
└── internal/
└── crypto/
└── sign.go (定义了 func Encrypt())你自己能用:你的
api/order.go依然可以正常导入Shop/internal/crypto并调用大写的Encrypt()。因为api是internal的兄弟(它们有共同的父亲SuperOrder)。外人绝对用不了:如果有用户尝试在自己的项目里
import "github.com/yourname/Shop/internal/crypto",Go 编译器会直接报错,根本不让他编译。
这下解决了痛点了
部分参考自:
Golang中文学习文档站



