6 Go语言的常量、枚举、作用域

本专栏将从基础开始,循序渐进,由浅入深讲解Go语言,希望大家都能够从中有所收获,也请大家多多支持。
查看相关资料与知识库
专栏地址:Go专栏
如果文章知识点有错误的地方,请指正!大家一起学习,一起进步。

文章目录

    • 常量
    • 练习 1.16 – 常量
      • 预期输出
    • 枚举
    • 作用域

常量

常量类似于变量,但其初始值不能更改。在需要代码运行时保持不变的值的情况下,使用常量非常有用。虽然可以将这些值硬编码到代码中以实现类似效果,但经验表明,虽然这些值在运行时不需要更改,但将来可能需要更改。如果发生这种情况,追踪和修复所有硬编码的值可能是一项繁琐且容易出错的任务。使用常量可以节省大量的后续维护工作。

常量声明类似于 var 语句。定义常量时,必须指定初始值。类型是可选的,如果省略,类型将会被推断。初始值可以是文字值或简单的表达式,并且可以使用其他常量的值。与 var 一样,可以在一个语句中声明多个常量。以下是常量声明的语法:

const <name> <type> = <value>
const (<name1> <type1> = <value1><name2> <type2> = <value2>…<nameN> <typeN> = <valueN>
)

练习 1.16 – 常量

在这个练习中,我们遇到了一个性能问题:我们的数据库服务器太慢了。我们将创建一个自定义内存缓存。我们会使用 Go 的 map 集合类型作为缓存。缓存中可以存储的项目数量有一个全局限制。我们将使用一个 map 来帮助跟踪缓存中的项目数量。我们需要缓存两种类型的数据:书籍和 CD。两者都使用 ID,因此我们需要一种方法来区分共享缓存中的两种类型的项目。我们需要一种方法来设置和获取缓存中的项目。

我们将设置缓存中的最大项目数量。我们还将使用常量添加前缀,以区分书籍和 CD。让我们开始吧:

  1. 创建一个新的文件夹,并在其中添加一个 main.go 文件。

  2. main.go 文件的顶部添加 main 包名:

    package main
    
  3. 导入我们需要的包:

    import "fmt"
    
  4. 创建一个表示全局限制大小的常量:

    const GlobalLimit = 100
    
  5. 创建一个 MaxCacheSize 常量,它是全局限制大小的 10 倍:

    const MaxCacheSize int = 10 * GlobalLimit
    
  6. 创建我们的缓存前缀:

    const (CacheKeyBook = "book_"CacheKeyCD = "cd_"
    )
    
  7. 声明一个 map 类型的变量,用于存储缓存,其中键和值都是字符串类型:

    var cache map[string]string
    
  8. 创建一个从缓存中获取项目的函数:

    func cacheGet(key string) string {return cache[key]
    }
    
  9. 创建一个在缓存中设置项目的函数:

    func cacheSet(key, val string) {
    
  10. 在这个函数中,检查 MaxCacheSize 常量,防止缓存超过这个大小:

      if len(cache)+1 >= MaxCacheSize {return}cache[key] = val
    }
    
  11. 创建一个从缓存中获取书籍的函数:

    func GetBook(isbn string) string {
    
  12. 使用书籍缓存前缀创建一个唯一的键:

      return cacheGet(CacheKeyBook + isbn)
    }
    
  13. 创建一个将书籍添加到缓存中的函数:

    func SetBook(isbn string, name string) {
    
  14. 使用书籍缓存前缀创建一个唯一的键:

      cacheSet(CacheKeyBook+isbn, name)
    }
    
  15. 创建一个从缓存中获取 CD 数据的函数:

    func GetCD(sku string) string {
    
  16. 使用 CD 缓存前缀创建一个唯一的键:

      return cacheGet(CacheKeyCD + sku)
    }
    
  17. 创建一个将 CD 添加到共享缓存中的函数:

    func SetCD(sku string, title string) {
    
  18. 使用 CD 缓存前缀常量为共享缓存构建一个唯一的键:

      cacheSet(CacheKeyCD+sku, title)
    }
    
  19. 创建 main() 函数:

    func main() {
    
  20. 通过创建一个 map 值来初始化缓存:

      cache = make(map[string]string)
    }
    
  21. 将一本书添加到缓存中:

      SetBook("1234-5678", "Get Ready To Go")
    
  22. 将 CD 添加到缓存中:

      SetCD("1234-5678", "Get Ready To Go Audio Book")
    
  23. 从缓存中获取并打印那本书:

      fmt.Println("Book :", GetBook("1234-5678"))
    
  24. 从缓存中获取并打印那张 CD:

      fmt.Println("CD :", GetCD("1234-5678"))
    
  25. 关闭 main() 函数:

    }
    
  26. 保存文件。然后,在新文件夹中运行:

    go run .
    

预期输出

在这个练习中,我们使用常量来定义在代码运行时不需要更改的值。我们用不同的语法选项声明了常量,有的指定了类型,有的则没有。我们既声明了单个常量,也在一个语句中声明了多个常量。

接下来,我们将查看与常量相关的变体,用于更紧密关联的值。

枚举

枚举是一种定义固定值列表的方式,这些值都是相关的。虽然 Go 语言没有内置的枚举类型,但它提供了 iota 工具,让我们可以使用常量定义自己的枚举。接下来,我们将探讨如何使用 iota 来实现枚举。

例如,在以下代码中,我们将一周的天数定义为常量。这个代码很适合使用 Go 的 iota 特性:

const (Sunday  = 0Monday  = 1Tuesday = 2Wednesday = 3Thursday = 4Friday  = 5Saturday = 6
)

使用 iota,Go 会帮助我们管理这样的列表。使用 iota,以下代码等同于上面的代码:

const (Sunday = iotaMondayTuesdayWednesdayThursdayFridaySaturday
)

通过 iota,我们可以自动为枚举分配值。使用 iota 使得创建和维护枚举更加方便,特别是在你需要在代码中间添加新值时。iota 是一个标识符,指示 Go 编译器从 0 开始为第一个值分配,后续值每次递增 1。在使用 iota 时,顺序是重要的。iota 还允许跳过值(使用 _),从不同的偏移量开始,甚至使用更复杂的计算。

接下来,我们将详细了解 Go 的变量作用域规则以及这些规则如何影响代码编写。

作用域

在 Go 中,所有变量都存在于一个作用域中。顶级作用域是包作用域。作用域可以包含子作用域。定义子作用域的方式有几种;最简单的理解方式是,当你看到 { 时,表示你开始了一个新的子作用域,而这个子作用域在遇到匹配的 } 时结束。父子关系是在代码编译时定义的,而不是在代码运行时。当访问变量时,Go 会查看变量定义的作用域。如果在当前作用域找不到该变量,Go 会查看父作用域,然后是祖父作用域,一直到包作用域。当找到匹配的变量时,Go 会停止查找。如果没有找到匹配的变量,则会报错。

换句话说,当你的代码使用一个变量时,Go 需要确定该变量的定义位置。它从当前代码的作用域开始查找。如果在该作用域内找到一个变量定义,则停止查找并使用该变量定义。如果找不到变量定义,则开始向上遍历作用域栈,直到找到具有该名称的变量。这个查找过程基于变量名称。如果找到的变量名称匹配但类型不正确,Go 会抛出错误。

在以下示例中,我们定义了一个 level 变量。无论在哪里使用 level,都会使用同一个变量:

package main
import "fmt"
var level = "pkg"
func main() {fmt.Println("Main start :", level)if true {fmt.Println("Block start :", level)funcA()}
}
func funcA() {fmt.Println("funcA start :", level)
}

输出结果如下:

Main start : pkg
Block start : pkg
funcA start : pkg

在这个示例中,我们创建了一个 level 的影子变量。这个新的 level 变量与包作用域中的 level 变量没有关系。当我们在块内打印 level 时,Go 运行时会在 main 的作用域中找到 level 变量,并停止查找。这导致新变量覆盖了包变量。你也可以看到它是一个不同的变量,因为它的类型不同,变量在 Go 中不能改变类型:

package main
import "fmt"
var level = "pkg"
func main() {fmt.Println("Main start :", level)// 创建一个影子变量level := 42if true {fmt.Println("Block start :", level)funcA()}fmt.Println("Main end :", level)
}
func funcA() {fmt.Println("funcA start :", level)
}

输出结果如下:

Main start : pkg
Block start : 42
funcA start : pkg
Main end : 42

Go 的静态作用域解析在调用 funcA 时发挥作用。因此,当 funcA 运行时,它仍然看到包作用域中的 level 变量。作用域解析不考虑 funcA 的调用位置。

你不能访问子作用域中定义的变量:

package main
import "fmt"
func main() {{level := "Nest 1"fmt.Println("Block end :", level)}// 错误:未定义: level//fmt.Println("Main end  :", level)
}

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

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

相关文章

【Python】主字符串中查找子字符串:滑动窗口、正则表达式、递归检查

一、题目 In this challenge, the user enters a stirng and a substring. You have to print the number of times that the substring occurs in the given string. String traversal will tack place from left to right, not from right to lef. NOTE: String letters ar…

Leetcode—426. 将二叉搜索树转化为排序的双向链表【中等】Plus

2024每日刷题&#xff08;148&#xff09; Leetcode—426. 将二叉搜索树转化为排序的双向链表 实现代码 /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node() {}Node(int _val) {val _val;left NULL;right NULL;}Node(int _val, Nod…

R包:plot1cell单细胞可视化包

介绍 plot1cell是用于单细胞数据seurat数据对象的可视化包。 安装 ## You might need to install the dependencies below if they are not available in your R library. bioc.packages <- c("biomaRt","GenomeInfoDb","EnsDb.Hsapiens.v86&qu…

无人机之起飞前准备

一、检查无人机状态 1、确保无人机的电池充满电或有足够的电量&#xff1b; 2、检查螺旋桨是否安装牢固&#xff0c;没有损坏&#xff1b; 3、确认无人机的固件是最新版本&#xff0c;以保证拥有最新的功能和修正。 二、选择合适的起飞地点 1、避免在人群密集或有障碍物的…

深入理解 Java17 新特性:Sealed Classes

0 关键总结 Java SE 15在2020年9月发布&#xff0c;预览功能引入“封闭类”(JEP 360)封闭类是一种限制哪些其他类或接口可扩展它的类或接口类似枚举&#xff0c;封闭类在领域模型中捕获替代方案&#xff0c;允许程序员和编译器推理其穷尽性封闭类对于创建安全的层次结构也很有…

iOS 创建一个私有的 CocoaPods 库

创建一个私有的 CocoaPods 库&#xff08;pod&#xff09;涉及几个步骤&#xff0c;包括设置私有的 Git 仓库、创建 Podspec 文件、发布到私有仓库等等。以下是详细步骤&#xff1a; 设置私有 Git 仓库 首先&#xff0c;在 GitHub、GitLab 或 Bitbucket 上创建一个新的私有仓库…

身份证如何查验真伪?C#身份证二要素、三要素接口集成

身份证不仅是我们的身份证明&#xff0c;更是社会生活中的“通行证”&#xff0c;现在人们的衣食住行都离不开身份证。但对于提供服务的平台而言&#xff0c;如何对用户提供的身份信息进行真伪核验便成为了一大难题。别担心&#xff0c;今天小编为服务平台带来了身份证二要素、…

MySQL:增删改查、临时表、授权相关示例

目录 概念 数据完整性 主键 数据类型 精确数字 近似数字 字符串 二进制字符串 日期和时间 MySQL常用语句示例 SQL结构化查询语言 显示所有数据库 显示所有表 查看指定表的结构 查询指定表的所有列 创建一个数据库 创建表和列 插入数据记录 查询数据记录 修…

Android 列表视频滑动自动播放—滑动过程自动播放(滑动播放页面卡顿优化)

上一篇文章我们RecyclerView列表滑动自动播放——Android 列表视频滑动自动播放—滑动过程自动播放(实现思路) 实际我们会发现滑动页面自动播放视频页面会卡顿&#xff0c;针对这个问题&#xff0c;我们可以优化一下代码&#xff0c;通过Handler.runnable()去实现计算播放视频…

力扣 232用栈实现队列

思路&#xff1a; 栈的特性是先进后出&#xff0c;队列是先进先出 因此用两个栈来模拟队列 要实现的功能包括 push 入队列 pop() 出队列 peek获取队列的最上元素 isempty 队列判空 push 正常操作 stin.push()&#xff0c;只要元素入栈就行&#xff0c;stout元素…

C++ Map Set的模拟实现

C Map Set的模拟实现 文章目录 前言一、Map 和 Set是什么&#xff1f;1.Set2.Map 二、困难点困难一、set和map中值的类型不同困难二、Map和Set中值不可修改困难三、红黑树中迭代器的和--1.2.- - 困难四、map中[ ] 运算符重载的实现1.修改红黑树以及Map和Set中insert的返回值1.修…

Three.js投射光线实现三维物体交互

<template><div id"webgl"></div> </template><script setup> import * as THREE from three //导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入 dat.gui import { GUI } from thre…

k8s v1.30 完整安装过程及CNI安装过程总结

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G技术研究。 博客内容主要围绕…

【ffmpeg命令入门】添加水印

文章目录 前言什么是水印&#xff1f;为什么要添加水印&#xff1f;ffmpeg添加水印添加图片水印添加文字水印基本使用方法drawtext的参数 总结 前言 在视频制作和编辑的过程中&#xff0c;添加水印是一个常见且重要的步骤。水印不仅可以保护版权&#xff0c;还能用于品牌宣传和…

使用LLaMA-Factory对Llama3-8B-Chinese-Chat进行微调

文章目录 模型及数据&#xff1a;模型下载数据 LLaMA-Factory启动拉取代码启动webui 模型训练数据导入数据预览设置模型路径配置参数及参数的保存开始训练 过程观察加载模型、对话模型导出、再次加载 模型及数据&#xff1a; 模型下载 使用基于中文数据训练过的 LLaMA3 8B 模…

同步状态的广播事件

定向活动广播 你可以直接将事件从一个状态广播到另一个状态&#xff0c;以同步同一图表中的并行&#xff08;AND&#xff09;状态。以下规则适用&#xff1a; 在事件广播期间&#xff0c;接收状态必须处于活动状态。 一个图表中的操作无法将事件广播到另一个图表的状态。 与无定…

大坝安全监测设备有哪些主要功能?

推荐型号&#xff1a;TH-WY1】大坝安全监测设备的主要功能包括以下几个方面&#xff1a; 1. **实时监测大坝的各项物理参数**&#xff1a;包括应变、位移、水位、流量等<sup>1</sup><sup>2</sup>。 2. **数据处理和分析**&#xff1a;对监测数据进行处…

CSS全部标签属性重置语法

简单介绍 每个浏览器默认的属性不同&#xff0c;像谷歌浏览器不设置的话&#xff0c;默认每个元素是有外边距margin的&#xff0c;有的浏览器列表还会带上序号&#xff0c;有的浏览器就没有。 所以为了让所有浏览器都一致&#xff0c;在写CSS开始前&#xff0c;我们都需要用C…

[Javascript】前端面试基础3【每日学习并更新10】

Web开发中会话跟踪的方法有那些 cookiesessionurl重写隐藏inputip地址 JS基本数据类型 String&#xff1a;用于表示文本数据。Number&#xff1a;用于表示数值&#xff0c;包括整数和浮点数。BigInt&#xff1a;用于表示任意精度的整数。Boolean&#xff1a;用于表示逻辑值…

【React1】React概述、基本使用、脚手架、JSX、组件

文章目录 1. React基础1.1 React 概述1.1.1 什么是React1.1.2 React 的特点声明式基于组件学习一次,随处使用1.2 React 的基本使用1.2.1 React的安装1.2.2 React的使用1.2.3 React常用方法说明React.createElement()ReactDOM.render()1.3 React 脚手架的使用1.3.1 React 脚手架…