首页 > 其他分享 >导包和包管理

导包和包管理

时间:2024-02-21 18:12:13浏览次数:34  
标签:管理 geometry package init 导包 go main rectangle

目录

一、什么是包

  • 和python类似,包就是一个个包含某种功能的代码文件,为了代码以后的可重用性与可读性更高,维护更方便,才引入的一个概念。
  • 与python不同的是,python中的包就是一个文件,导包就是导文件,而go中,包以文件夹为基础,导包为导文件夹
  • 没有包的概念,就会把所有代码、方法全写在一个文件中,这对于一个项目来说,想想是不是就很可怕
  • 属于某一个包的源文件都应该放置于一个单独命名的文件夹里。且按照 Go 的惯例,应该用包名命名这个文件夹,在这个目录下的所有文件都属于这个包

二、main函数和main包

  • 所有可执行的 Go 程序都必须包含一个 main 函数。这个函数是程序运行的入口。main 函数应该放置于 main 包中,main 包是go自带的包。而python是没有这种限制的

  • package packagename 这行代码指定了某一源文件属于一个包。它应该放在每一个源文件的第一行

三、包管理

以下总体的目录结构:

src
    geometry
        geometry.go
        rectangle
            rectprops.go
bin
	geometry.exe  
	
// 执行 go build geometry 命令来编译上述程序。该命令会在 geometry 文件夹内搜索拥有 main 函数的文件。在这里,它找到了 geometry.go。接下来,它编译并产生一个名为 geometry (在 windows 下是 geometry.exe)的二进制文件,该二进制文件放置于工作区的 bin 文件夹

1. main包

// 在 geometry.go 中
package main 

import "fmt"

func main() {  
    fmt.Println("Geometrical shape properties")
}

2. 创建自定义包

  • 创建一个自定义包 rectangle,它有一个计算矩形的面积和对角线的函数。

    属于某一个包的源文件都应该放置于一个单独命名的文件夹里。按照 Go 的惯例,应该用包名命名该文件夹。

    因此,我们在 geometry 文件夹中,创建一个命名为 rectangle 的文件夹。在 rectangle 文件夹中,所有文件都会以 package rectangle 作为开头,因为它们都属于 rectangle 包

  • 注意:在 Go 中,任何以大写字母开头的变量或者函数才是能被导出的名字。其它包 只能 访问这些指定的被导出的函数和变量。在这里,我们需要在 main 包中访问 Area 和 Diagonal 函数,因此会将它们的首字母大写

  • 在创建的 rectangle 文件夹中,再创建一个名为 rectprops.go 的文件,内容如下

  • // rectprops.go
    package rectangle
    
    import "math"
    
    func Area(len, wid float64) float64 {  
        area := len * wid
        return area
    }
    
    func Diagonal(len, wid float64) float64 {  
        diagonal := math.Sqrt((len * len) + (wid * wid))
        return diagonal
    }
    

3. 导包

  • 为了使用自定义包,我们必须要先导入它。导入自定义包的语法为 import path。我们必须指定自定义包相对于工作区内 src 文件夹的相对路径。我们目前的文件夹结构是:

  • 1. 目录结构
    src
        geometry
            geometry.go
            rectangle
                rectprops.go
    
    
    
    2. **********在geometry.go中导入这个自定义的包***********
    
    // geometry.go
    package main 
    
    import (  
        "fmt"
        "geometry/rectangle" // 导入自定义包,只导入目录
    )
    
    func main() {  
        var rectLen, rectWidth float64 = 6, 7
        fmt.Println("Geometrical shape properties")
        /*Area function of rectangle package used*/
        fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth))
        /*Diagonal function of rectangle package used*/
        fmt.Printf("diagonal of the rectangle %.2f ", rectangle.Diagonal(rectLen, rectWidth))
    }
    

四、init 函数和包的初始化

  • 所有包都可以包含一个 init 函数。init 函数不应该有任何返回值类型和参数,在我们的代码中也不能显式地调用它。init 函数的形式如下

  • func init() {  
    }
    
  • init 函数可用于执行初始化任务,也可用于在开始执行之前验证程序的正确性。

    包的初始化顺序如下:

    1. 首先初始化包级别(Package Level)的变量
    2. 紧接着调用 init 函数。包可以有多个 init 函数(在一个文件或分布于多个文件中),它们按照编译器解析它们的顺序进行调用。
  • 如果一个包导入了另一个包,会先初始化被导入的包。

  • 尽管一个包可能会被导入多次,但是它只会被初始化一次

1. 实例-验证包的初始化顺序

(1)修改 rectprops.go

  • 首先在 rectprops.go 文件中添加了一个 init 函数
// rectprops.go
package rectangle

import "math"  
import "fmt"

/*
 * init function added
 */
func init() {  
    fmt.Println("rectangle package initialized")
}
func Area(len, wid float64) float64 {  
    area := len * wid
    return area
}

func Diagonal(len, wid float64) float64 {  
    diagonal := math.Sqrt((len * len) + (wid * wid))
    return diagonal
}

(2)修改geometry.go

  • 其次对 geometry.go 做了如下修改:
    1. 变量 rectLenrectWidth 从 main 函数级别移到了包级别。
    2. 添加了 init 函数。当 rectLen 或 rectWidth 小于 0 时,init 函数使用 log.Fatal 函数打印一条日志,并终止了程序。
// geometry.go
package main 

import (  
    "fmt"
    "geometry/rectangle" // 导入自定义包
    "log"
)

// 1. 包级别变量
var rectLen, rectWidth float64 = 6, 7 


// 2. init 函数会检查长和宽是否大于0

func init() {  
    println("main package initialized")
    if rectLen < 0 {
        log.Fatal("length is less than zero")
    }
    if rectWidth < 0 {
        log.Fatal("width is less than zero")
    }
}

func main() {  
    fmt.Println("Geometrical shape properties")
    fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth))
    fmt.Printf("diagonal of the rectangle %.2f ",rectangle.Diagonal(rectLen, rectWidth))
}

(3)运行结果

  • 理论上main 包的初始化顺序为:

    1. 首先初始化被导入的包。因此,首先初始化了 rectangle 包
    2. 接着初始化了包级别的变量 rectLenrectWidth
    3. 调用 init 函数
    4. 最后调用 main 函数
  • // 打印结果与理论符合
    
    rectangle package initialized  
    main package initialized  
    Geometrical shape properties  
    area of rectangle 42.00  
    diagonal of the rectangle 9.22
    

(4)再修改 geometry.go

将 geometry.go 中的 var rectLen, rectWidth float64 = 6, 7 改为 var rectLen, rectWidth float64 = -6, 7。
我们把 rectLen 初始化为负数

// 运行结果

rectangle package initialized  
main package initialized  
2017/04/04 00:28:20 length is less than zero

/*
会首先初始化 rectangle 包,然后是 main 包中的包级别的变量 rectLen 和 rectWidth。rectLen 为负数,因此当运行 init 函数时,程序在打印 length is less than zero 后终止
*/

五、实现导包而不用

  • 在go中,导入了包或变量,却不在代码中使用它们,这在 Go 中都是非法的。当这么做时,编译器是会报错的。其原因是为了避免导入过多未使用的包或定义了过多的变量,从而导致编译时间显著增加

  • 变量还好,但是再开发之前,我们都会习惯先将要用的包导好,再进行后续开发,但是这就与上面说的相矛盾,此时就可以使用错误屏蔽器来避免

1. 错误导包

// geometry.go
package main 

import (
    "geometry/rectangle" // 导入自定的包
)
func main() {

}

// 导了而不用,会报错 geometry.go:6: imported and not used: "geometry/rectangle"

2. 错误屏蔽器

// geometry.go
package main

import (  
    "geometry/rectangle" 
)

var _ = rectangle.Area // 错误屏蔽器

func main() {

}


/*
var _ = rectangle.Area 这一行屏蔽了错误。我们应该了解这些错误屏蔽器(Error Silencer)的动态,在程序开发结束时就移除它们,包括那些还没有使用过的包。由此建议在 import 语句下面的包级别范围中写上错误屏蔽器
*/

3. 空白标识符避错

  • 有时候我们导入一个包,只是为了确保它进行了初始化,而无需使用包中的任何函数或变量。例如,我们或许需要确保调用了 rectangle 包的 init 函数,而不需要在代码中使用它。这种情况也可以使用空白标识符

  • // geometry.go
    package main 
    
    import (
        _ "geometry/rectangle" 
    )
    func main() {
    
    }
    
    // 运行这个的程序,会输出 rectangle package initialized。尽管在所有代码里,我们都没有使用这个包,但还是成功初始化了它
    

标签:管理,geometry,package,init,导包,go,main,rectangle
From: https://www.cnblogs.com/Mcoming/p/18025907

相关文章

  • 操作系统实训_基于多级目录的文件管理系统
    title:操作系统实训_基于多级目录的文件管理系统author:fxydate:2022-07-0719:18:00tags:实训category:实训readmore:truedescription:SDUT操作系统实训,基于多级目录的文件管理系统,c++1、实训报告:github实训报告2、代码://基于多级文件目录的文件管理系统#includ......
  • Java人力资源管理系统源码(含数据库)-springboot+vue+mysql
    EHR人力资源管理系统是一种利用现代技术,如云计算、大数据等,来实现企业人力资源信息电子化、流程自动化的系统。它覆盖了人力资源管理的各个方面,从招聘、考勤、绩效到薪酬、社保公积金等,为企业提供一站式的解决方案。​1.招聘管理:-职位发布:系统支持在线发布职位信息,吸引候选人......
  • SRM数字化采购管理平台-招投标管理系统-供应链协同|招投标|询比价(源码及功能分析)
    前言:通过数字化手段,采购管理可以更加高效、准确和透明。数字化采购管理系统可以集成各个流程环节,实现数据共享和协同工作,提高采购效率和成本控制能力。同时,数字化采购管理也有助于加强与供应商之间的沟通和协作,优化供应链管理,提升企业的竞争力。1.供应商准入:1)定义:评估供应商的......
  • home-assistant core 源码粗读--如何管理多用户-用户存储(二)
    程序中搜索User, 很容易命中homeassistant/auth/models.py程序中大量使用了attr.s进行模型的声明。上篇说过dataclass,以及BaseModel,区别见: https://www.modb.pro/db/412679文件中定义了5个模型,这里只需要猜测他们的意思即可,这里重点分析User。程序中搜索User, 很容易命......
  • 项目开发中的权限管理设计方案详解
    为什么需要权限管理日常工作中权限的问题时时刻刻伴随着我们,程序员新入职一家公司需要找人开通各种权限,比如网络连接的权限、编码下载提交的权限、监控平台登录的权限、运营平台查数据的权限等等。在很多时候我们会觉得这么多繁杂的申请给工作带来不便,并且如果突然想要查一些数......
  • Linux文件权限管理 chmod命令
    chmod命令用于改变Unix/linux系统中文件或目录的访问权限。这些权限决定了哪些用户可以对文件或目录进行读取,写入或执行操作。chmod命令有两种主要的用法:符号模式(symbolicmode)和八进制模式(octalmode)1.符号模式(Symbolic Mode)符号模式允许你使用u(用户,即文件所有者),g(组,即文件......
  • linux用户管理
    在Linux系统中,文件权限管理是一项重要的任务,它决定了哪些用户或用户组可以对文件执行哪些操作。Linux文件系统的权限管理基于三个核心概念:文件所有者(owner)、文件所属用户组(group)和其他用户(others)。文件权限对于维护系统的安全性和保护文件的机密性至关重要。请务必仔细考虑文件......
  • 米兔定位电话解绑管理员重置办法
    米兔定位电话解绑管理员需要以下资料 米兔定位电话的IMEI,86开头的。 需要知道原先一位成员的电话号码在定位电话里插入一张正常使用的卡,用于接收验证短信IMEI找回:可以在App中找到,右上角设置-》点击二维码图标-》点击二维码字样打开盖子,里面有个很小的二维......
  • ssts-hospital-web-master项目实战记录二:版本管理-git
    记录时间:2024-02-211.VSCode打开项目(1)文件→打开文件夹,对应的英文为File→OpenFolder(2)打开效果如下 2.VSCode本地项目托管 (1)打开终端:Terminal→NewTerminal(2)生成仓库:git init输入 git命令git init (3)添加到暂存区:git add.输入 git命令git add. (4)提......
  • windows node管理工具nvm
    nvm全名node.jsversionmanagement,是一个nodejs的版本管理工具。通过它可以安装和切换不同版本的nodejs。首先最重要的是:一定要卸载已安装的NodeJS,否则会发生冲突。 卸载程序确保在Node.js没有在后台运行的情况下,进行卸载。可以先打开软件,关闭后到控制面板中找到node.js......