【Go语言圣经2.6】

目标

概念

  1. GOPATH模型

    • GOPATH:GOPATH 是一个环境变量,指明 Go 代码的工作区路径。
    • 工作区通常包含三个目录:
      • src:存放源代码,按照导入路径组织。例如,包 gopl.io/ch2/tempconv 应存放在 $GOPATH/src/gopl.io/ch2/tempconv 中。
      • pkg:编译后生成的包文件(中间产物)。
      • bin:可执行文件。
    • 在 GOPATH 模型中,包的导入路径直接对应于 src 目录下的子目录结构
      • 例如,import "gopl.io/ch2/tempconv" 表示编译器将在 $GOPATH/src/gopl.io/ch2/tempconv 下寻找该包的源代码。
  2. Go module 模型(现代依赖管理方式)

    • Go module
      • Go module 是从 Go 1.11 开始引入的,不再强制要求代码必须放在 GOPATH 内。
      • 每个模块有一个 go.mod 文件,其中定义了模块路径(作为导入路径的前缀)和依赖项及其版本。
    • 模块根目录可以放在任意位置,go.mod 中指定的模块路径决定了包的导入路径前缀。
      • 例如,如果 go.mod 声明模块为 gopl.io/ch2/tempconv,则该模块中的包可以直接用该路径导入,无需放在 GOPATH 内。
    • 优势:
      • 自动管理依赖版本,支持版本控制;
      • 使得项目结构更灵活,不受 GOPATH 限制;
      • 编译工具会根据 go.mod 自动解析和下载依赖。
  3. 构建工具如何根据不同模型处理依赖和编译项目

    • go build 命令
      • 在 GOPATH 模型下,go build 根据 GOPATH/src 中的目录结构找到并编译包;
      • 在 module 模型下,go build 会读取当前目录或上级目录中的 go.mod 文件来确定模块范围,并自动处理依赖。
    • 导入包时的区别
      • 在 GOPATH 模型下,你的代码必须位于 GOPATH/src 中;
      • 在 module 模型下,你可以在任何地方创建项目,依赖管理由 go.mod 文件控制。
  4. 包的作用和意义

    • 模块化与封装

      Go 语言中的包类似于其他语言中的库或模块,其目的是将相关代码组织在一起,实现模块化编程。

      • 封装:包内部的实现细节可以隐藏,仅公开需要被外部使用的部分。
      • 单独编译和重用:每个包可以单独编译,也能在不同程序中复用,提高代码可维护性和协作效率。
  5. 命名空间

    每个包都有自己独立的命名空间。当不同包中存在同名的函数或类型,外部引用时加上包前缀,这避免了名称冲突

  6. 导出规则

    • 包中的标识符(如变量、常量、函数、类型等)只有首字母大写时才是导出的,也就是对外可见的;否则只在包内部可见。这为包内部实现细节的隐藏提供了简单而有效的机制。
  7. 文件组织与包结构

    • 一个包通常由一个或多个以 .go 为后缀的源文件组成。这些文件必须以相同的包声明开始。例如,一个包可能存放在 $GOPATH/src/gopl.io/ch2/tempconv 目录中,其导入路径就是 gopl.io/ch2/tempconv
  8. 多个源文件协同工作

    • 包级别的声明(类型、变量、常量、函数)在同一包内的所有源文件中都是共享的,就像所有代码都写在一个文件中一样。
    • 可以将不同功能或逻辑拆分到多个文件中,提高代码组织和可维护性。例如:
      • tempconv.go:放置包级的常量、类型、以及为这些类型定义的方法(如 String())。
      • conv.go:专门放置温度转换函数,如 CToFFToC
  9. 导入包

    • 导入路径与包名
      • 每个包都有一个全局唯一的导入路径,如 "gopl.io/ch2/tempconv"。这个路径由构建工具解析,通常对应一个目录。
      • 包的名字通常在包声明处指定,惯例上包名和导入路径的最后一个字段相同(例如 tempconv
  10. 包注释

    • 在每个包的源文件开头紧跟着的注释称为包注释,它应该简明扼要地说明包的功能。
      • 通常只需在一个文件中包含完整的包注释,如果包比较复杂,也可以单独放在 doc.go 文件中。
  11. 开发工具支持

    goimports 和 gofmt

    • 这些工具可以自动添加或删除导入语句,并格式化代码,保持代码风格一致,有助于日常开发。

要点

导入语句的写法与使用

  1. 在源文件中通过 import 语句导入包

    import ("fmt""gopl.io/ch2/tempconv"
    )
  2. 导入后,包内导出的标识符(首字母大写的)可以通过“包名.标识符”访问,例如:

    tempconv.CToF(tempconv.BoilingC)
    
    • 如果导入后不使用该包,编译器会报错。这鼓励程序员只导入真正需要的包,保持依赖清晰。
  3. 如果有命名冲突或为了简洁,可以将导入的包绑定到另一个名字**(重命名导入)**

    import tconv "gopl.io/ch2/tempconv"
    

    然后用 tconv.CToF 访问包中的内容。

包的初始化

  1. 初始化顺序规则
    • 包中的全局变量(包级变量)的初始化遵循先依赖后顺序:

      • 变量的初始化顺序是按照它们在源代码中出现的顺序进行。
      • 当一个包被导入时,所有包级变量会在 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 包执行前,所有依赖包都已完成初始化。
  2. 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 
        }
        

语言特性

习题

  1. 重写PopCount函数,用一个循环代替单一的表达式。

    // 假设已经定义查数数组pc[256]
    func PopCountLoop(x uint64) int{var sum intfor i:=0; i<8; i++{sum += int(pc[byte(x)]) // 取最低8位x >> 8}
    }
    
  2. 用移位算法重写PopCount函数,每次测试最右边的1bit,然后统计总数。

    func PopCountShift(x uint64) int {var sum intfor i := 0; i < 64; i++ {sum += int(x & 1)x >>= 1}return sum
    }
    
  3. 表达式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
    }
    

总结与补充

  1. 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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34752.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT入门笔记2

目录 一、前言 二、串口助手实现 2.1、串口 2.1.1、可用串口信息-QSerialPortInfo 2.1.2、打开串口-QSerialPort 2.1.3、串口发送接收信息 2.2、定时器-QTimer 2.3、常用属性类型转换&#xff08;会更新&#xff09; 2.4、子控件组规则命名优化 一、前言 这个是学习Q…

DeepSeek(3):DeepSeek R1 提示词⼯程

1 提示词⼯程 5W1H&#xff08;What, Who, When, Where, Why, How&#xff09;是⼀种常⽤的信息收集和指令下达的⽅法。以下是根据这个⽅法为DeepSeek R1模型下指令的例⼦&#xff0c;以“学习⼤模型应⽤开发”为例&#xff1a; &#xff08;1&#xff09;What&#xff08;是什…

Linux入门 全面整理终端 Bash、Vim 基础命令速记

Linux入门 2025 超详细全面整理 Bash、Vim 基础命令速记 刚面对高级感满满的 终端窗口是不是有点懵&#xff1f;于是乎&#xff0c;这份手册就是为你准备的高效学习指南&#xff01;我把那些让人头大的系统设置、记不住的命令都整理成了对你更友好的格式&#xff0c;让你快速学…

RBA+minibatch的尝试

目录 还是咬着牙来写 RBA了 JAX JAX->TORCH torch tensor的变形 pytorch怎么把一个【3,3,5】的tensor变成【3,10,5】&#xff0c;多的用0填充 pytorch如何把shape【100】转成【100,1】 把torch shape【100,1】变成【100】 SQUEEZE grad_fn 不能两次反向传播 还…

Jupyter notebook的安装与使用

jupyter notebook的安装需要在已经安装配置好的conda环境下 win r 打开运行窗口 输入cmd回车 在cmd窗口中输入以下命令 conda install jupyter notebook安装完成后启动 jupyter notebook 也是在cmd窗口 输入 : jupyter notebook运行成功后第一次打开的时候需要选择一个浏览…

如何在Ubuntu上构建编译LLVM和ISPC,以及Ubuntu上ISPC的使用方法

之前一直在 Mac 上使用 ISPC&#xff0c;奈何核心/线程太少了。最近想在 Ubuntu 上搞搞&#xff0c;但是 snap 安装的 ISPC不知道为什么只能单核&#xff0c;很奇怪&#xff0c;就想着编译一下&#xff0c;需要 Clang 和 LLVM。但是 Ubuntu 很搞&#xff0c;他的很多软件版本是…

特殊的数字排序

0特殊的数字排序 - 蓝桥云课 问题描述 小明被挑选去参加一个ACM比赛。他的任务是解决一个很特别的问题&#xff1a;给定一个整数数组&#xff0c;但是只能通过交换任意两个数的方式来排序。听起来很简单对吗&#xff1f;但是这个问题的难点在于&#xff0c;只有某些数字是可以…

汽车感性负载-智能高边钳位能量计算

随着汽车电子技术的发展&#xff0c;新的电子电气架构下&#xff0c;越来越多的执行部件在车身出现&#xff0c;比如电磁阀、风机、水泵、油泵、雨刮继电器等常用的执行器&#xff0c; 它们一般都表现为感性特点。驱动这些负载的最简单和最常见的方法是将它们连接到高边侧开关(…

量化交易学习笔记02:双均线策略

双均线策略示例 个股&#xff1a;中国平安 回测日期&#xff1a;2022-5-1至2023-5-1 短均线&#xff1a;5天 长无线&#xff1a;10天 代码&#xff1a; def initialize(context):# 初始化此策略# 设置我们要操作的股票池, 这里我们只操作一支股票# """标的&qu…

利用余弦相似度在大量文章中找出抄袭的文章

我前面的2篇文章分别讲了如果利用余弦相似度来判断2篇文章的相似度&#xff0c;来确定文章是否存在抄袭&#xff0c;和余弦相似度的原理&#xff0c;即余弦相似度到底是怎么来判断文章的相似性高低的等等。这一篇再说下&#xff0c;对于文章字数多和大量文章时&#xff0c;如果…

在 Kaggle 中绘制中文乱码解决

在 Kaggle 中绘制中文时&#xff0c;需要设置 Matplotlib 的字体&#xff0c;否则中文会显示为乱码。可以使用 SimHei&#xff08;黑体&#xff09;或 Microsoft YaHei&#xff08;微软雅黑&#xff09;。 解决方案 使用 matplotlib 设置中文字体在 Kaggle 安装 SimHei 字体 …

在 Ubuntu 服务器上使用宝塔面板搭建博客

&#x1f4cc; 介绍 在本教程中&#xff0c;我们将介绍如何在 Ubuntu 服务器 上安装 宝塔面板&#xff0c;并使用 Nginx PHP MySQL 搭建一个博客&#xff08;如 WordPress&#xff09;。 主要步骤包括&#xff1a; 安装宝塔面板配置 Nginx PHP MySQL绑定域名与 SSL 证书…

Linux线程

1.线程概念 在一个程序里的一个执行路线就叫做线程(thread)&#xff0c;更准确定义&#xff1a;线程是一个进程内部的控制序列 进程至少有一个执行路线&#xff0c;线程在进程内部运行&#xff0c;本质是在进程地址空间内运行&#xff0c;在Linux系统中&#xff0c;CPU眼中&a…

【TI MSPM0】GPIO学习

一、文件样例查找 以GPIO软件轮询为例 下面的四个文件夹分别为不同开发环境提供支持 二、工程导入 1.点击file-点击import project 2.点击browse 3.找到对应的文件打开&#xff0c;选择 推荐使用ticlang,能够提供更加优化的效率 点击finish 三、工程学习 1.readme 文件 &a…

二叉树的基本操作与实现:C语言深度剖析

目录 代码整体框架 1. #define _CRT_SECURE_NO_WARNINGS 2. 头文件引入 3. typedef int BTtype; 4. 二叉树节点结构体定义 二叉树的创建 1. BuyNode 函数 2. CreatNode 函数 二叉树的遍历 前序遍历 中序遍历 后序遍历 二叉树属性的计算 节点个…

深入解析 Latent Diffusion Model(潜在扩散模型,LDMs)(代码实现)

深入解析 Latent Diffusion Model&#xff1a;从传统 Diffusion Model 到高效图像生成的进化 近年来&#xff0c;生成模型在图像合成领域取得了显著进展&#xff0c;其中 Diffusion Model&#xff08;扩散模型&#xff0c;DMs&#xff09;以其出色的生成质量和理论上的稳健性逐…

线性回归原理推导与应用(五):波士顿房价预测实战

波士顿房价是一个非常经典的多元线性回归入门案例数据集。波士顿房价预测数据集包含了可能会影响房价的十三个因素&#xff0c;并给出了实际的房价&#xff08;单位为万美元&#xff09; 波士顿房价数据集数据集下载地址&#xff1a;https://www.kaggle.com/datasets/altavish…

基于CATIA二次开发的低音炮腔体容积精准计算技术详解

一、功能概述 本工具通过PySide6与CATIA V5深度集成&#xff0c;实现了低音炮上下腔体内体积的自动化测量系统。系统采用三维实体建模法进行容积计算&#xff0c;相较于传统手工计算方式&#xff0c;精度提升可达0.5%。主要功能模块包括&#xff1a; 壳体特征自动识别动态草图…

向量数据库原理及选型

向量数据库 什么是向量什么是向量数据库原理应用场景 向量数据库的选型主流向量数据库介绍向量数据库对比主流向量数据库对比表 选型建议 什么是向量 向量是一组有序的数值&#xff0c;表示在多维空间中的位置或方向。向量通常用一个列或行的数字集合来表示&#xff0c;这些数…

IE代理切换器v1.2免费版

虽然IE浏览器已经过时了&#xff0c;但很多其他浏览器&#xff0c;比如谷歌浏览器的代理服务器设置&#xff0c;都还是基于IE浏览器来进行设置的&#xff0c;如果你的工作场景需要切换不同的代理服务器来访问网络&#xff0c;那这款工具适合你&#xff0c;目前该工具可以实现IE…