【Go语言圣经2.6】
目标
概念
-
GOPATH模型
- GOPATH:GOPATH 是一个环境变量,指明 Go 代码的工作区路径。
- 工作区通常包含三个目录:
- src:存放源代码,按照导入路径组织。例如,包
gopl.io/ch2/tempconv应存放在$GOPATH/src/gopl.io/ch2/tempconv中。 - pkg:编译后生成的包文件(中间产物)。
- bin:可执行文件。
- src:存放源代码,按照导入路径组织。例如,包
- 在 GOPATH 模型中,包的导入路径直接对应于
src目录下的子目录结构- 例如,
import "gopl.io/ch2/tempconv"表示编译器将在$GOPATH/src/gopl.io/ch2/tempconv下寻找该包的源代码。
- 例如,
-
Go module 模型(现代依赖管理方式)
- Go module
- Go module 是从 Go 1.11 开始引入的,不再强制要求代码必须放在 GOPATH 内。
- 每个模块有一个
go.mod文件,其中定义了模块路径(作为导入路径的前缀)和依赖项及其版本。
- 模块根目录可以放在任意位置,
go.mod中指定的模块路径决定了包的导入路径前缀。- 例如,如果
go.mod声明模块为gopl.io/ch2/tempconv,则该模块中的包可以直接用该路径导入,无需放在 GOPATH 内。
- 例如,如果
- 优势:
- 自动管理依赖版本,支持版本控制;
- 使得项目结构更灵活,不受 GOPATH 限制;
- 编译工具会根据
go.mod自动解析和下载依赖。
- Go module
-
构建工具如何根据不同模型处理依赖和编译项目
- go build 命令
- 在 GOPATH 模型下,
go build根据 GOPATH/src 中的目录结构找到并编译包; - 在 module 模型下,
go build会读取当前目录或上级目录中的go.mod文件来确定模块范围,并自动处理依赖。
- 在 GOPATH 模型下,
- 导入包时的区别
- 在 GOPATH 模型下,你的代码必须位于 GOPATH/src 中;
- 在 module 模型下,你可以在任何地方创建项目,依赖管理由
go.mod文件控制。
- go build 命令
-
包的作用和意义
-
模块化与封装
Go 语言中的包类似于其他语言中的库或模块,其目的是将相关代码组织在一起,实现模块化编程。
- 封装:包内部的实现细节可以隐藏,仅公开需要被外部使用的部分。
- 单独编译和重用:每个包可以单独编译,也能在不同程序中复用,提高代码可维护性和协作效率。
-
-
命名空间
每个包都有自己独立的命名空间。当不同包中存在同名的函数或类型,外部引用时加上包前缀,这避免了名称冲突
-
导出规则
- 包中的标识符(如变量、常量、函数、类型等)只有首字母大写时才是导出的,也就是对外可见的;否则只在包内部可见。这为包内部实现细节的隐藏提供了简单而有效的机制。
-
文件组织与包结构
- 一个包通常由一个或多个以
.go为后缀的源文件组成。这些文件必须以相同的包声明开始。例如,一个包可能存放在$GOPATH/src/gopl.io/ch2/tempconv目录中,其导入路径就是gopl.io/ch2/tempconv。
- 一个包通常由一个或多个以
-
多个源文件协同工作
- 包级别的声明(类型、变量、常量、函数)在同一包内的所有源文件中都是共享的,就像所有代码都写在一个文件中一样。
- 可以将不同功能或逻辑拆分到多个文件中,提高代码组织和可维护性。例如:
- tempconv.go:放置包级的常量、类型、以及为这些类型定义的方法(如
String())。 - conv.go:专门放置温度转换函数,如
CToF和FToC。
- tempconv.go:放置包级的常量、类型、以及为这些类型定义的方法(如
-
导入包
- 导入路径与包名
- 每个包都有一个全局唯一的导入路径,如
"gopl.io/ch2/tempconv"。这个路径由构建工具解析,通常对应一个目录。 - 包的名字通常在包声明处指定,惯例上包名和导入路径的最后一个字段相同(例如
tempconv)
- 每个包都有一个全局唯一的导入路径,如
- 导入路径与包名
-
包注释
- 在每个包的源文件开头紧跟着的注释称为包注释,它应该简明扼要地说明包的功能。
- 通常只需在一个文件中包含完整的包注释,如果包比较复杂,也可以单独放在 doc.go 文件中。
- 在每个包的源文件开头紧跟着的注释称为包注释,它应该简明扼要地说明包的功能。
-
开发工具支持
goimports 和 gofmt
- 这些工具可以自动添加或删除导入语句,并格式化代码,保持代码风格一致,有助于日常开发。
要点
导入语句的写法与使用
-
在源文件中通过
import语句导入包import ("fmt""gopl.io/ch2/tempconv" ) -
导入后,包内导出的标识符(首字母大写的)可以通过“包名.标识符”访问,例如:
tempconv.CToF(tempconv.BoilingC)- 如果导入后不使用该包,编译器会报错。这鼓励程序员只导入真正需要的包,保持依赖清晰。
-
如果有命名冲突或为了简洁,可以将导入的包绑定到另一个名字**(重命名导入)**
import tconv "gopl.io/ch2/tempconv"然后用
tconv.CToF访问包中的内容。
包的初始化
- 初始化顺序规则
-
包中的全局变量(包级变量)的初始化遵循先依赖后顺序:
- 变量的初始化顺序是按照它们在源代码中出现的顺序进行。
- 当一个包被导入时,所有包级变量会在
main()函数执行前完成初始化。
var a = b + c // a 是第三个初始化的变量 var b = f() // b 是第二个初始化的变量(依赖 c) var c = 1 // c 是第一个初始化的变量 func f() int { return c + 1 }- 在这个例子中,初始化时会确保
c已经赋值,这样b才能正确调用f()。
-
包初始化顺序与依赖
- 当一个包 A 导入包 B 时,B 包会先于 A 包初始化。
- 这种自下而上的初始化方式确保 main 包执行前,所有依赖包都已完成初始化。
-
- init函数
- init 函数的作用
- init 函数用于在包初始化时执行额外的初始化逻辑。
- 每个源文件可以包含多个 init 函数,且它们会在包初始化时按照声明顺序自动调用。
- init 函数不能被显式调用或引用,仅用于初始化工作。
- 示例
-
构建辅助数据表或进行复杂的初始化运算。例如在 popcount 包中,用 init 函数预生成一个查表数组:
var pc [256]bytefunc init() {for i := range pc {pc[i] = pc[i/2] + byte(i&1)} } -
如果初始化过程较复杂,可以采用匿名函数直接在变量声明中完成初始化
var pc [256]byte = func()(pc [256]byte) {for i := range pc{pc[i] = pc[i/2] + byte(i&1)}return }
-
- init 函数的作用
语言特性
习题
-
重写PopCount函数,用一个循环代替单一的表达式。
// 假设已经定义查数数组pc[256] func PopCountLoop(x uint64) int{var sum intfor i:=0; i<8; i++{sum += int(pc[byte(x)]) // 取最低8位x >> 8} } -
用移位算法重写PopCount函数,每次测试最右边的1bit,然后统计总数。
func PopCountShift(x uint64) int {var sum intfor i := 0; i < 64; i++ {sum += int(x & 1)x >>= 1}return sum } -
表达式x&(x-1)用于将x的最低的一个非零的bit位清零。使用这个算法重写PopCount函数
- 二进制,x-1 会把 x 中最右边的那个“1”变成“0”,并把后面所有的 0 变成 1。(当你给 x 减 1 时,从最右边开始,所有连续的 0 都借1减1,直到碰到第一个 1,这个 1 就变成 0。)
- 当你把 x 和 x-1 做与操作时,只有当两个对应位置都是 1 时,结果才为 1。由于 x-1 在原来最低1的位置已经变成了 0,所以 x&(x-1) 在那个位置肯定是 0,并且之前为0的低位不会改变——这就把x的最低的一个非零的bit位清零
func PopCountClear(x uint64) int {var count intfor x != 0 {x &= x - 1 // 清除最低位的1count++}return count }
总结与补充
-
popcount算法解读
func PopCount(x uint64) int {return int(pc[byte(x>>(0*8))] +pc[byte(x>>(1*8))] +pc[byte(x>>(2*8))] +pc[byte(x>>(3*8))] +pc[byte(x>>(4*8))] +pc[byte(x>>(5*8))] +pc[byte(x>>(6*8))] +pc[byte(x>>(7*8))]) }想象一下你有一本“数字图鉴”,里面记着0到255这256个数字,每个数字旁边都写着它的“1的个数”。这个图鉴就是那个预先计算好的表格(pc数组)。
- 预先计算图鉴(init函数)
- 做法: 对于0到255中的每个数字,我们算一算它的二进制写法里有几个1,然后把这个数字和它的1的个数存进图鉴里。
- 秘诀: 计算一个二进制数字的1的个数时,我们可以把它分解为“除以2后的数字”里的1的个数,再加上“最后一位是否为1”。比如说,如果数字6(二进制110),我们先看6/2等于3(二进制11),再加上6最后一位(0),结果就是2个1。
- 你把一个数字除以2(也就是右移一位),其实就是把最右边那一位扔掉了。那么,这个数字中1的总数就等于“扔掉最后一位后剩下的数字中的1的个数”加上“刚刚扔掉的那一位是否是1”。
- 用图鉴快速数1的个数(PopCount函数)
- 大数字切小块: 当我们有一个很大的64位数字时,不用检查64个数字,而是把它分成8个8位的小数字。
- 表达式
x >> (k*8)的意思是把数字 x 向右移动 k*8 位,这样原本在第 k 个8位区域的数字就会移动到最右边。 - 使用
byte()把移动后的结果截取成一个8位的数字(一个字节)。
- 表达式
- 查表加和: 对每个8位的小数字,直接在图鉴里查出它有几个1,然后把8个结果加起来,就知道整个64位数字里有多少个1。
- 大数字切小块: 当我们有一个很大的64位数字时,不用检查64个数字,而是把它分成8个8位的小数字。
- 预先计算图鉴(init函数)
相关文章:
【Go语言圣经2.6】
目标 概念 GOPATH模型 GOPATH:GOPATH 是一个环境变量,指明 Go 代码的工作区路径。工作区通常包含三个目录: src:存放源代码,按照导入路径组织。例如,包 gopl.io/ch2/tempconv 应存放在 $GOPATH/src/gopl.i…...
Python的基本知识
Python是一种广泛使用的高级编程语言,以下是其基本用法的介绍: 变量与数据类型 - 变量定义:直接赋值即可创建变量,如 x 5 , name "John" 。 - 数据类型:包括 int (整数…...
QEMU源码全解析 —— 块设备虚拟化(4)
接前一篇文章:QEMU源码全解析 —— 块设备虚拟化(3) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM源码解析与应用》 —— 李强,机械工业出版社 类模板是创建类的模式_创建类是的模版-CSDN博客<...
34个适合机械工程及自动化专业【论文选题】
论文选题具有极其重要的意义,它直接关系到论文的质量、价值以及研究的可行性和顺利程度。选题明确了研究的具体领域和核心问题,就像给研究旅程设定了方向和目的地。例如,选择 “人工智能在医疗影像诊断中的应用” 这一选题,就确定…...
langchain框架
LangChain的架构分为多个层次,支持Python和JavaScript生态 基础层(langchain-core):提供LLM抽象接口、表达式语言(LCEL)等核心机制,支持超过70种主流模型(如GPT-4、Llama࿰…...
RHCE(RHCSA复习:npm、dnf、源码安装实验)
七、软件管理 7.1 rpm 安装 7.1.1 挂载 [rootlocalhost ~]# ll /mnt total 0 drwxr-xr-x. 2 root root 6 Oct 27 21:32 hgfs[rootlocalhost ~]# mount /dev/sr0 /mnt #挂载 mount: /mnt: WARNING: source write-protected, mounted read-only. [rootlocalhost ~]# [rootlo…...
Mybatis3 调用存储过程
1. 数据库MySQL,user表 CREATE TABLE user (USER_ID int NOT NULL AUTO_INCREMENT,USER_NAME varchar(100) NOT NULL COMMENT 用户姓名,AGE int NOT NULL COMMENT 年龄,CREATED_TIME datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,CREATED_BY varchar(100) NOT NUL…...
解决 openeuler 系统 docker 下载慢,docker 镜像加速
一、步骤说明 1. 编辑 Docker 配置文件 Docker 的镜像源配置文件路径为 /etc/docker/daemon.json。如果该文件不存在,则需要先创建目录和文件。 # 创建目录(如果不存在) sudo mkdir -p /etc/docker# 编辑配置文件(使用 nano 或…...
HiPixel开源AI驱动的图像超分辨率的原生macOS 应用程序,使用 SwiftUI 构建并利用 Upscayl 强大的 AI 模型
一、软件介绍 文末提供程序和源码下载 HiPixel是一个开源程序基于SwiftUI构建的macOS原生应用程序,用于AI驱动的图像超分辨率,并利用Upscayl的强大AI模型。 二、软件特征 具有 SwiftUI 界面的原生 macOS 应用程序使用 AI 模型进行高质量图像放大通过 G…...
Python 正则表达式模块 re
Python 正则表达式模块 re flyfish 一、正则表达式基础 1. 什么是正则表达式? 正则表达式(Regular Expression, RE)是一种用于匹配、查找和替换文本模式的工具,由普通字符(如字母、数字)和特殊字符&…...
[RN 实践有效]Expo+cross-env配置项目环境变量
首先,从中可以看出,cross-env的主要作用是跨平台设置环境变量,而Expo项目通常通过app.config.js或.env文件来管理这些变量。需要强调安装cross-env的必要性,以及如何在package.json中正确配置脚本命令。 接下来,用户的问题是关于Expo中cross-env的详细配置,因此需要分步骤…...
缓存和客户端数据存储体系(Ark Data Kit)--- 应用数据持久化(首选项持久化、K-V、关系型数据库)持续更新中...
Core File Kit做怎删改查操作不便,用Ark Data Kit。 功能介绍 ArkData (方舟数据管理)为开发者提供数据存储、数据管理和数据同步能力,比如联系人应用数据可以保存到数据库中,提供数据库的安全、可靠以及共享访问等管…...
ES 使用geo point 查询离目标地址最近的数据
需求描述:项目中需要通过经纬度坐标查询目标地所在的行政区。 解决思路大致有种,使用es和mysql分别查询。 1、使用es进行查询 将带有经纬度坐标的省市区数据存入es中,mappings字段使用geo point类型,索引及查询dsl如下。 geo p…...
本地部署OpenManus及原理介绍
概述: 最近Minaus特别火,随后开源社区就有项目尝试复刻Minaus,项目名称为OpenManus,原理是用推理模型为决策者,将我们输入的问题进行分解后调用本地工具执行。 OpenManus安装: 本人在Ubuntu桌面版本上安装…...
高效手机检测:视觉分析技术的优势
在当今社会,手机已成为人们日常生活和工作中不可或缺的工具。然而,在某些特定场合,如考场、工作场所等,手机的使用却可能带来负面影响。因此,如何有效监测和防止在这些场合偷用手机的行为,成为了一个亟待解…...
Java 多线程编程:提升系统并发处理能力!
多线程是 Java 中实现并发任务执行的关键技术,能够显著提升程序在多核处理器上的性能以及处理多任务的能力。本文面向初级到中级开发者,从多线程的基本定义开始,逐步讲解线程创建、状态管理、同步机制、并发工具以及新兴的虚拟线程技术。每部…...
Linux实时内核稳定性案例
稳定性问题分析 RT_RUNTIME_SHARE案例死锁问题Linux-rt下卡死之hrtimer分析Linux内核宕机案例 -mmap空指针Linux Hung Task分析过程...
解决 VSCode SSH 连接报错:“REMOTE HOST IDENTIFICATION HAS CHANGED” 的问题
问题描述 在使用 VSCode 通过 SSH 连接远程服务器时,我们可能会遇到类似如下的错误日志: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! ... Offending ED25519 key in C:\Users\DELL/…...
Spring Boot配置类原理、Spring Boot核心机制理解,以及实现自动装置的底层原理
目的:从底层源码角度分析 Spring Boot 配置类以及自动装载的底层原理 文章目录 1. Spring Boot 配置类实现自动装载1.1 @Configuration注解1.2 @Configuration 注解完成 bean 注入流程图1.3 @ConfigurationProperties注解赋值2. Spring Boot的核心机制:自动装配2.1 @SpringBo…...
淘宝API vs 爬虫:合规获取实时商品数据的成本与效率对比
以下是淘宝 API 和爬虫在合规获取实时商品数据方面的成本与效率对比: 成本对比 淘宝 API 开发成本:需要申请开发者账号并获取 API 权限,部分敏感或高频访问的接口可能需要额外的审核或付费。开发过程中需要按照平台规定进行编程,相…...
01-Canvas-使用fabric初始
fabric官网: https://fabric5.fabricjs.com/demos/ 创建画布并绘制 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…...
CMake简单入门
简介 CMake 是一个开源的跨平台构建系统生成工具,旨在简化和自动化项目的构建过程。它主要用于管理和控制软件构建的过程,特别是在处理复杂的项目结构和多个平台时。CMake 并不直接进行编译或链接,而是生成本地构建系统所需的文件࿰…...
树莓派 连接 PlutoSDR 教程
在树莓派5上安装PlutoSDR(ADALM-Pluto)的驱动程序,主要需要安装相关的库和工具,以便与PlutoSDR通信,比如libiio和libad9361,并确保系统能够识别设备。由于树莓派5运行的是基于Linux的系统(通常是…...
【时时三省】(C语言基础)用printf函数输出数据3
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 ( 5 ) e格式符。 用格式声明%e指定以指数形式输出实数。如果不指定输出数据所占的宽度和数字部分的小数位数,许多C编译系统(如VisualC)会自动给出数字部分…...
Git使用(二)--如何配置 GitHub 远程仓库及本地 Git 环境
在日常的开发过程中,使用版本控制工具 Git 是一个非常重要的技能,特别是对于管理和协作开发。通过 GitHub,我们可以轻松地进行代码版本管理和共享。这篇博客将带您一步步学习如何配置 Git 环境并将本地仓库与 GitHub 远程仓库连接起来。 一、…...
在Pycharm配置conda虚拟环境的Python解释器
〇、前言 今天在配置python解释器时遇到了这样的问题 经过一下午自行摸索、上网搜寻后,终于找到的解决的方案,遂将该方法简要的记录下来,以备后用,并希望能帮助到有同样问题或需求的朋友:) 我所使用的软件的版本如下,假…...
CURL一文通
文章目录 1.什么是curl2.curl可以发送什么请求3.常见curl发http相关请求怎么写4.curl带上的参数分别有什么,可以怎么用5.进阶用法6.常见错误以及学习指导建议 1.什么是curl 是利用URL语法在命令行下工作的开源文件传输工具。尤其被广泛应用的在linux系统下。 2.cu…...
零基础keil:设置注释快捷键
1.打开快捷键设置: 在Keil中,选择菜单栏中的“Settings”,然后选择“Shortcuts”来打开快捷键设置界面。 2.选择注释命令: 在快捷键设置界面中,找到与注释相关的命令,如“Comment Selection”࿰…...
Java中关于Optional的 orElse 操作,以及 orElse 与 orElseGet 的区别
文章目录 1. 大概说明2. 详细分析2.1 .orElse 操作2.2 .orElse 的作用:避免空指针异常2.3 为什么要用?2.4 orElseGet如何使用2.5 orElse和orElseGet的区别 1. 大概说明 这篇文章的目的是为了说明: orElse 如何使用orElseGet 如何使用两者的…...
TCP/IP协议中三次握手(Three-way Handshake)与四次挥手(Four-way Wave)
TCP/IP协议中三次握手(Three-way Handshake)与四次挥手(Four-way Wave) 一、TCP三次握手(Three-way Handshake)二、TCP四次挥手(Four-way Wave)三、常见问题解答总结为什么三次握手不…...
