前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手把手教会你带你理解Go语言中的包

手把手教会你带你理解Go语言中的包

作者头像
Go进阶者
发布2021-01-22 10:54:05
7720
发布2021-01-22 10:54:05
举报
文章被收录于专栏:Go语言进阶学习

前言

Hey,大家好呀,我是星期八,咱们原来写的代码,都是缩在一块的,久而久之咱们可能都能感觉到冗余。

所以今天就来学一下包这个东西,将咱们的代码拆分一下。

包可以理解为存放多个.go的文件夹但是这个文件夹下面的第一行的package后面跟的不再是main了而是文件名,就像这样。

目录

clacmain.go文件是同级的。

可以看到clac文件夹下的add.go第一行不再是main而是文件夹名 clac同理sub.go第一行也是。

这个只是单独的解释包的定义方式没有实际意义。

包的注意事项

如果这个文件夹要当包使用文件夹名中不能包含_

导入包

上面我们知道了包是如何定义的。

并且在和main.go同级的项目目录下建了一个clac包。

clac包下有俩个文件一个是add.go一个是sub.go两个文件夹分别都有对应的方法。问题来了???

那我们如何在main.go中使用上述建立的包调用里面的方法呢?

这就是要导入它们了。

示例代码

代码语言:javascript
复制
package main

import (
   "a3_course/clac"
)

func main() {
   clac.Add()
   clac.Sub()
}

执行结果

可以看到在main.go中成功调用了clac包中的代码。

注:导入包只需要导入到文件夹即可就可以调用下面所有的方法和属性不再需要包名.xx.go这种方式。

如上述导入calc不管calc下面有几个.go文件里面的方法和属性都可以随便调用。

导入包注意事项

上述我是直接通过

代码语言:javascript
复制
import (
   "a3_course/clac"
)

这种方式导入包的但是在你们那可能不太行。

因为我使用的是go mod所以通过项目目录/包名导入。

如果你没有使用go mod是传统的方式那么导入包需要从GOPATH/src进行导入这里不举例了。

如果还不会使用go mod记得爬楼看以往文章,上面有教程,一篇文章教会你如何使用Go语言Modules,记得要拥抱未来噢。

可见性

可见性在其他语言中有的叫私有成员之类的称呼在Go中就叫可见性。

Go中可见性很简单不管是变量还是函数还是结构体。

首字母大写在哪都能访问。

首字母小写只能在当前包使用。

示例

clac/add.go文件

代码语言:javascript
复制
package clac

import (
    "fmt"
)

//这是一个公开的变量
var Name = "张三"

//这是一个私有变量,只能在 clac 包中访问
var age = 18

//这是一个公开的函数
func Add() {
    fmt.Println("我是做加法的...")
}

main.go文件

代码语言:javascript
复制
func main() {
    clac.Add()
    clac.Sub()
    fmt.Println(clac.Name)
    //clac中的age是小写开头,属于私有变量,所以其他包不能访问
    //fmt.Println(clac.age) // cannot refer to unexported name clac.age
}

访问私有变量报错信息。

结构体可见性的问题

我们知道结构体是有字段的但是你想过结构体的字段大小写问题吗?

代码语言:javascript
复制
type Student struct {
    Name string
    age  int
}
//age是小写开头

结构体名开头是不是大写影响的主要是在其他包里面的调用权限问题。

结构体字段开头是不是大写主要影响的是调用里面字段的问题一个明显的问题就是序列化。

更多结构体的相关文章,可前往:Go语言基础之结构体(春日篇)

示例代码

代码语言:javascript
复制
package main

import (
    "encoding/json"
    "fmt"
)

type Student struct {
    Name string
    age  int
}

func main() {
    var s1 = Student{
        Name: "张三",
        age:  18,
}
    serializeBytes,err:=json.Marshal(s1)
    if err != nil {
        fmt.Println("序列化失败")
}
    serializeStr := string(serializeBytes)
    fmt.Println(serializeStr)
}

执行结果

会发现执行结果少了一个age

这是因为age小写开头属于私有变量。

但是json.Marshal(s1)这个已经属于其他包了所以访问不到age

包别名

我们在导入包时其实还可以自定义包名就像Python中的 from xx import xx as yy

示例代码

代码语言:javascript
复制
package main

//给 clac 包起别名
import cl "a3_course/clac"

func main() {
    cl.Add()
}

执行结果

匿名导入包

匿名导入包就是相当于不用这个包里面的东西。

可能有人就会问了那不用包里面的东西,那还导入作甚呢?

嗯...这个匿名导入包主要要跟包的一个init方法有关系咱们先继续看。

匿名导入包示例代码

代码语言:javascript
复制
package main

//前面有个 _ 就表示是匿名导入
import _ "a3_course/clac"

func main() {

}

包的init方法

其实每次导入其他包的时候都会执行包的init方法。

示例

代码语言:javascript
复制
//clac/add.go
package clac

import "fmt"

func init() {
  fmt.Println("clac/add.go/init")
}
func Sub() {
  fmt.Println("我是做减法的...")
}

//clac/sub.go
package clac

import "fmt"

func init() {
  fmt.Println("clac/sub.go/init")
}
func Sub() {
  fmt.Println("我是做减法的...")
}

main.go

代码语言:javascript
复制
package main

import _ "a3_course/clac"

func main() {

}

执行结果

可以发现我虽然是匿名导入包但是仍然还是执行了add.gosub.go下的init方法。

这就说明了一个问题导入一个包会执行这个包下面所有的init方法不管下面有几个.go文件。

注:包的init方法不能写参数也不能有返回值init方法只能在导入时调用不能主动调用。

init方法比main方法更提前一步执行

多个包嵌套导入时init方法执行的顺序

代码较多就直接如图所示了:

这意思是main.go导入了otherother包导入了inner包 ,套娃。

先看一下执行结果

执行结果是innerinit方法先执行然后是ohterinit方法。

其实本质是碰到import就执行被导入包的init方法。

它的图应该是这样子的。

意思是main导入了ohter那就执行otherinit方法。

但是在导入ohter时发现other导入了inner那就执行innerinit方法。

总结

上述我们学习了Go基础之包,学习了如何创建包组织包导入包的注意事项包的权限问题(大写开头所有可见)匿名导入包init方法多个init方法注意事项。

可能有点不太好理解,但是还是要坚持,一定要多敲两次。

如果在操作过程中有任何问题,记得下面讨论区留言,我们看到会第一时间解决问题。

我是码农星期八,如果觉得还不错,记得动手点赞一下哈。感谢你的观看。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Go语言进阶学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
    • 目录
    • 包的注意事项
    • 导入包
    • 导入包注意事项
    • 可见性
    • 结构体可见性的问题
    • 包别名
    • 匿名导入包
    • 包的init方法
    • 多个包嵌套导入时init方法执行的顺序
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档