南沙区做网站,免费天眼查,计算机网络技术就业方向网站开发,上海招聘网站建设本专栏将从基础开始#xff0c;循序渐进#xff0c;由浅入深讲解Go语言#xff0c;希望大家都能够从中有所收获#xff0c;也请大家多多支持。 查看相关资料与知识库 专栏地址:Go专栏 如果文章知识点有错误的地方#xff0c;请指正#xff01;大家一起学习#xff0c;… 本专栏将从基础开始循序渐进由浅入深讲解Go语言希望大家都能够从中有所收获也请大家多多支持。 查看相关资料与知识库 专栏地址:Go专栏 如果文章知识点有错误的地方请指正大家一起学习一起进步。 文章目录 常量练习 1.16 – 常量预期输出 枚举作用域 常量
常量类似于变量但其初始值不能更改。在需要代码运行时保持不变的值的情况下使用常量非常有用。虽然可以将这些值硬编码到代码中以实现类似效果但经验表明虽然这些值在运行时不需要更改但将来可能需要更改。如果发生这种情况追踪和修复所有硬编码的值可能是一项繁琐且容易出错的任务。使用常量可以节省大量的后续维护工作。
常量声明类似于 var 语句。定义常量时必须指定初始值。类型是可选的如果省略类型将会被推断。初始值可以是文字值或简单的表达式并且可以使用其他常量的值。与 var 一样可以在一个语句中声明多个常量。以下是常量声明的语法
const name type value
const (name1 type1 value1name2 type2 value2…nameN typeN valueN
)练习 1.16 – 常量
在这个练习中我们遇到了一个性能问题我们的数据库服务器太慢了。我们将创建一个自定义内存缓存。我们会使用 Go 的 map 集合类型作为缓存。缓存中可以存储的项目数量有一个全局限制。我们将使用一个 map 来帮助跟踪缓存中的项目数量。我们需要缓存两种类型的数据书籍和 CD。两者都使用 ID因此我们需要一种方法来区分共享缓存中的两种类型的项目。我们需要一种方法来设置和获取缓存中的项目。
我们将设置缓存中的最大项目数量。我们还将使用常量添加前缀以区分书籍和 CD。让我们开始吧 创建一个新的文件夹并在其中添加一个 main.go 文件。 在 main.go 文件的顶部添加 main 包名 package main导入我们需要的包 import fmt创建一个表示全局限制大小的常量 const GlobalLimit 100创建一个 MaxCacheSize 常量它是全局限制大小的 10 倍 const MaxCacheSize int 10 * GlobalLimit创建我们的缓存前缀 const (CacheKeyBook book_CacheKeyCD cd_
)声明一个 map 类型的变量用于存储缓存其中键和值都是字符串类型 var cache map[string]string创建一个从缓存中获取项目的函数 func cacheGet(key string) string {return cache[key]
}创建一个在缓存中设置项目的函数 func cacheSet(key, val string) {在这个函数中检查 MaxCacheSize 常量防止缓存超过这个大小 if len(cache)1 MaxCacheSize {return}cache[key] val
}创建一个从缓存中获取书籍的函数 func GetBook(isbn string) string {使用书籍缓存前缀创建一个唯一的键 return cacheGet(CacheKeyBook isbn)
}创建一个将书籍添加到缓存中的函数 func SetBook(isbn string, name string) {使用书籍缓存前缀创建一个唯一的键 cacheSet(CacheKeyBookisbn, name)
}创建一个从缓存中获取 CD 数据的函数 func GetCD(sku string) string {使用 CD 缓存前缀创建一个唯一的键 return cacheGet(CacheKeyCD sku)
}创建一个将 CD 添加到共享缓存中的函数 func SetCD(sku string, title string) {使用 CD 缓存前缀常量为共享缓存构建一个唯一的键 cacheSet(CacheKeyCDsku, title)
}创建 main() 函数 func main() {通过创建一个 map 值来初始化缓存 cache make(map[string]string)
}将一本书添加到缓存中 SetBook(1234-5678, Get Ready To Go)将 CD 添加到缓存中 SetCD(1234-5678, Get Ready To Go Audio Book)从缓存中获取并打印那本书 fmt.Println(Book :, GetBook(1234-5678))从缓存中获取并打印那张 CD fmt.Println(CD :, GetCD(1234-5678))关闭 main() 函数 }保存文件。然后在新文件夹中运行 go run .预期输出
在这个练习中我们使用常量来定义在代码运行时不需要更改的值。我们用不同的语法选项声明了常量有的指定了类型有的则没有。我们既声明了单个常量也在一个语句中声明了多个常量。
接下来我们将查看与常量相关的变体用于更紧密关联的值。
枚举
枚举是一种定义固定值列表的方式这些值都是相关的。虽然 Go 语言没有内置的枚举类型但它提供了 iota 工具让我们可以使用常量定义自己的枚举。接下来我们将探讨如何使用 iota 来实现枚举。
例如在以下代码中我们将一周的天数定义为常量。这个代码很适合使用 Go 的 iota 特性
…
const (Sunday 0Monday 1Tuesday 2Wednesday 3Thursday 4Friday 5Saturday 6
)
…使用 iotaGo 会帮助我们管理这样的列表。使用 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 : 42Go 的静态作用域解析在调用 funcA 时发挥作用。因此当 funcA 运行时它仍然看到包作用域中的 level 变量。作用域解析不考虑 funcA 的调用位置。
你不能访问子作用域中定义的变量
package main
import fmt
func main() {{level : Nest 1fmt.Println(Block end :, level)}// 错误未定义: level//fmt.Println(Main end :, level)
}