代码跟雅思阅读一样长?拆!接触 Module 与 Package 【说人话的 Golang 小白入门 - EP02】

简介


上一篇 【说人话的 Golang 小白入门】EP01 - 问候世界? Hello World! 刚完成 Hello World,想必小伙伴都想赶紧把各种库用起来开发自己想要的程序!

但是 但是 但是 等一下 等一下 等一下。。。 先來说说怎么初始化 Module 吧!

(你问 Module 是什么?先动手再说!)

动手环节


PART 1: Module 初始化

先创建一个文件夹 hello-go,后续教程的代码都将整理在这个文件夹底下

  • 以下会以 hello-go/{文件名} 示意文件所在位置
➜ mkdir hello-go

然后指定你的 Module 名称,以初始化 go.mod 文件

  • 然而!Module 命名正是本章最大的挑战!我第一次的时候在这卡了有半个小时!
  • 可以先参考一下一些公开库的命名吧
    • 原生库
      • 单词,如 fmt,math,strings
    • gopkg.in 上的项目名一般是下面两种
      • CASE 1: gopkg.in/{仓库名}.{版本号}, 如 gopkg.in/yaml.v2
      • CASE 2gopkg.in/{用户名}/{仓库名}.{版本号}, 如 gopkg.in/go-playground/validator.v9
    • github.com
      • github.com/{用户名}/{仓库名},如 github.com/aws/aws-sdk-go
  • 可以看出来前缀的作用就是为了区分不同用户/机构/来源的开源库,所以
    • 本地自用的话按 {个人代号}/{项目名} 命名就好
    • 准备上传到类似 github.com 的网站公开的话就按 github.com/{用户名}/{仓库名} 命名
➜ go mod init kabuski/hello-go
go: creating new go.mod: module kabuski/hello-go

查看创建的 go.mod,可以看到指定的 Module 名称和当前使用的 Go 版本

➜ cat go.mod               
module hello-go

go 1.16

这样 Module 就初始化好喇!

PART 2: Package 定义和引用

这个时候我们把之前 Hello World 如下拆解

hello-go
│
└─ hello
│  └─ hello.go
│ 
└─ main.go
└─ go.mod
// hello/hello.go
package hello

import "fmt"

func SayHello(){
	fmt.Println("Hahahaha Hello World")
	fmt.Printf("Welcome to %s's GoLang Tutorial~~", "KabuSki")
}
// main.go
package main

import "kabuski/hello-go/hello"

func main(){
    hello.SayHello()
}

这样代码就准备好了~还是一样的命令运行程序试试

➜ go run main.go 
 
Hahahaha Hello World !!!
Welcome to KabuSki's GoLang Tutorial ~~!!!

哒哒!拆腾了一轮,没有一点区別!(你踏马在逗我 ?

代码解读


Part 1: 上面都干了什么?

首先,我们把打印文字的函数搬到了 main.go 以外的文件 hello/hello.go 中的 func SayHello

main.go 裡怎么引出这个函数呢?正是下面这一行

import "kabuski/hello-go/hello"

机智的你一定看出来了,前缀 "kabuski/hello-go" 正是前面 mod init 指定的 Module 名称

那后缀的 hello 呢?是文件夾名称?还是 hello.go 中首行声名的 Package 名称?

3..

2..

1..

0.. 哒哒!答案是文件夹名称

在 Golang 中,Package 的引用是由 {Module}/{路径} 指定的。

相对地,想要引用某段代码文件中声名的函数或变量的话,它就必须被包装为一个 Module 中的一个 Package 的成员。只要你的项目包含不只一个代码文件,你都需要将他作为 Module 初始化 。 

Part 2: 引用 Package 之后怎么调用它的成员?

main.go 中能看到,我們以下面这一行调用了 package hello 的函数 func SayHello

hello.SayHello()

注意这裡 SayHello 是大写字母开头的,只有大写字母开头的函数、成员等才可以被调用,关于这一点会在后续章节说明。

那么问题来了,这裡的 hello 是文件夾名称还是 hello.go 中首行声名的 Package 名称?

3..

2..

1..

0.. 哒哒!答案是 Package 名称

这时候你应该猜到了,文件夹  Package 是一对一的关系,一个文件夹下的代码文件都属于同一个 Package,一个文件夹下的代码文件首行声明的 package 也必须相同,否则会报错。

但是文件夹下的文件夹和这个文件夹不属于同一个 Package (你搁这套娃呢?

还是举个具体的栗子吧,以下面这个为例

hello-go
│
└─ hello
│  └─ english
│  │  └─ hello_in_english.go
│  │
│  └─ hello.go
│ 
└─ main.go
└─ go.mod

这裡 hello/english/hello_in_english.go 可以声明为 package english 而不是 package hello。但无论你在 hello_in_english.go 中声明的 package 名是不是 hello,如果你只 import "kabuski/hello-go/hello" 的话,那都不能直接引用 hello_in_english.go 裡的成员。


那我可以直接 import "kabuski/hello-go/hello/english" 吗?

可以!

那为什么要套这么多层文件夹?

这个单纯是为了让开发人员能更好地从逻辑上组织代码,但怎么组织一个项目的代码文件正正体现了开发人员的水平。

那 Package 名称可以跟文件夹名称不一样吗?

可以!

如果这是自己用的代码,那没关系,除了给自己添堵以外没什么毛病。

但如果你是团队合作开发的话,答应我別这么干,会出人命。

结语


本章主要解決了在 Golang 语言裡,如何在一个文件中引用另一个文件定义的函数,引入了 Module 和 Package 的概念。

更深入的说明还是留到下一章吧,下一章见~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值